summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2016-05-26 16:05:17 -0700
committerSunny Goyal <sunnygoyal@google.com>2016-05-27 18:23:29 -0700
commitda4fe1a6244457f144e0a331cada3ada17157809 (patch)
tree71a921324999c5c61598d08b1de864c426c8bc8e /src/com/android
parentc54c701a94e213503d0c6d2ff414e91a50c14133 (diff)
downloadandroid_packages_apps_Trebuchet-da4fe1a6244457f144e0a331cada3ada17157809.tar.gz
android_packages_apps_Trebuchet-da4fe1a6244457f144e0a331cada3ada17157809.tar.bz2
android_packages_apps_Trebuchet-da4fe1a6244457f144e0a331cada3ada17157809.zip
Moving the QSB to the workspace grid.
The QSB will only be resent on the first screen of the workspace covering the full width of the first row. If will not be movable. The first screen of the workspace will not be movable. The searchDropTargetBar no longer contains the QSB (it can be renamed in aseparate cl). Refactoring all QSB related logic by moving it to a custom view inflated only using xml. Change-Id: Icb4fd6eb855df1af15f685961c38351bf4fd4f4a
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/launcher3/CellLayout.java2
-rw-r--r--src/com/android/launcher3/Launcher.java237
-rw-r--r--src/com/android/launcher3/LauncherAppState.java1
-rw-r--r--src/com/android/launcher3/LauncherAppWidgetHost.java15
-rw-r--r--src/com/android/launcher3/LauncherAppWidgetHostView.java4
-rw-r--r--src/com/android/launcher3/LauncherModel.java15
-rw-r--r--src/com/android/launcher3/LauncherProvider.java13
-rw-r--r--src/com/android/launcher3/LauncherProviderChangeListener.java2
-rw-r--r--src/com/android/launcher3/PagedView.java6
-rw-r--r--src/com/android/launcher3/PinchAnimationManager.java8
-rw-r--r--src/com/android/launcher3/QsbContainerView.java271
-rw-r--r--src/com/android/launcher3/SearchDropTargetBar.java75
-rw-r--r--src/com/android/launcher3/Utilities.java36
-rw-r--r--src/com/android/launcher3/Workspace.java61
-rw-r--r--src/com/android/launcher3/model/GridSizeMigrationTask.java38
-rw-r--r--src/com/android/launcher3/util/GridOccupancy.java2
16 files changed, 430 insertions, 356 deletions
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index e3bb5fa72..cfaa6a34d 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -2708,7 +2708,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
/**
* Indicates whether this item can be reordered. Always true except in the case of the
- * the AllApps button.
+ * the AllApps button and QSB place holder.
*/
public boolean canReorder = true;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 13e451a27..6a95a9092 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -45,20 +45,16 @@ import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -113,7 +109,6 @@ import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.WidgetsModel;
-import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.pageindicators.PageIndicatorLine;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
@@ -183,6 +178,9 @@ public class Launcher extends Activity
static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
"com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
+ public static final String ACTION_APPWIDGET_HOST_RESET =
+ "com.android.launcher3.intent.ACTION_APPWIDGET_HOST_RESET";
+
// Type: int
private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
// Type: int
@@ -197,9 +195,6 @@ public class Launcher extends Activity
static final String INTRO_SCREEN_DISMISSED = "launcher.intro_screen_dismissed";
static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed";
- private static final String QSB_WIDGET_ID = "qsb_widget_id";
- private static final String QSB_WIDGET_PROVIDER = "qsb_widget_provider";
-
/** The different states that Launcher can be in. */
enum State { NONE, WORKSPACE, WORKSPACE_SPRING_LOADED, APPS, APPS_SPRING_LOADED,
WIDGETS, WIDGETS_SPRING_LOADED }
@@ -219,8 +214,19 @@ public class Launcher extends Activity
private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
@Thunk static int NEW_APPS_ANIMATION_DELAY = 500;
- private final BroadcastReceiver mCloseSystemDialogsReceiver
- = new CloseSystemDialogsIntentReceiver();
+ private final BroadcastReceiver mUiBroadcastReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ closeSystemDialogs();
+ } else if (ACTION_APPWIDGET_HOST_RESET.equals(intent.getAction())) {
+ if (mAppWidgetHost != null) {
+ mAppWidgetHost.startListening();
+ }
+ }
+ }
+ };
@Thunk Workspace mWorkspace;
private View mLauncherView;
@@ -255,8 +261,6 @@ public class Launcher extends Activity
@Thunk WidgetsContainerView mWidgetsView;
@Thunk WidgetsModel mWidgetsModel;
- private AppWidgetHostView mQsb;
-
private Bundle mSavedState;
// We set the state in both onCreate and then onNewIntent in some cases, which causes both
// scroll issues (because the workspace may not have been measured yet) and extra work.
@@ -464,7 +468,8 @@ public class Launcher extends Activity
Selection.setSelection(mDefaultKeySsb, 0);
IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- registerReceiver(mCloseSystemDialogsReceiver, filter);
+ filter.addAction(ACTION_APPWIDGET_HOST_RESET);
+ registerReceiver(mUiBroadcastReceiver, filter);
mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation);
// In case we are on a device with locked rotation, we should look at preferences to check
@@ -739,10 +744,6 @@ public class Launcher extends Activity
} else if (resultCode == RESULT_OK) {
addAppWidgetImpl(appWidgetId, mPendingAddInfo, null,
mPendingAddWidgetInfo, ON_ACTIVITY_RESULT_ANIMATION_DELAY);
-
- // When the user has granted permission to bind widgets, we should check to see if
- // we can inflate the default search bar widget.
- getOrCreateQsbBar();
}
return;
} else if (requestCode == REQUEST_PICK_WALLPAPER) {
@@ -1056,7 +1057,6 @@ public class Launcher extends Activity
if (!isWorkspaceLoading()) {
getWorkspace().reinflateWidgetsIfNecessary();
}
- reinflateQSBIfNecessary();
if (DEBUG_RESUME_TIME) {
Log.d(TAG, "Time spent in onResume: " + (System.currentTimeMillis() - startTime));
@@ -1368,6 +1368,7 @@ public class Launcher extends Activity
mWorkspace.setHapticFeedbackEnabled(false);
mWorkspace.setOnLongClickListener(this);
mWorkspace.setup(dragController);
+ mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */);
dragController.addDragListener(mWorkspace);
// Get the search/delete/uninstall bar
@@ -1393,7 +1394,6 @@ public class Launcher extends Activity
dragController.addDropTarget(mWorkspace);
if (mSearchDropTargetBar != null) {
mSearchDropTargetBar.setup(this, dragController);
- mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
}
if (mAppInfoDropTargetBar != null) {
mAppInfoDropTargetBar.setup(this, dragController);
@@ -1999,7 +1999,7 @@ public class Launcher extends Activity
((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
.removeAccessibilityStateChangeListener(this);
- unregisterReceiver(mCloseSystemDialogsReceiver);
+ unregisterReceiver(mUiBroadcastReceiver);
LauncherAnimUtils.onDestroyActivity();
@@ -2052,10 +2052,9 @@ public class Launcher extends Activity
appSearchData = new Bundle();
appSearchData.putString("source", "launcher-search");
}
- Rect sourceBounds = new Rect();
- if (mSearchDropTargetBar != null) {
- sourceBounds = mSearchDropTargetBar.getSearchBarBounds();
- }
+
+ // TODO send proper bounds.
+ Rect sourceBounds = null;
boolean clearTextImmediately = startSearch(initialQuery, selectInitialQuery,
appSearchData, sourceBounds);
@@ -2465,19 +2464,6 @@ public class Launcher extends Activity
}
/**
- * Re-listen when widget host is reset.
- */
- @Override
- public void onAppWidgetHostReset() {
- if (mAppWidgetHost != null) {
- mAppWidgetHost.startListening();
- }
-
- // Recreate the QSB, as the widget has been reset.
- bindSearchProviderChanged();
- }
-
- /**
* Launches the intent referred by the clicked shortcut.
*
* @param v The view representing the clicked shortcut.
@@ -3497,105 +3483,6 @@ public class Launcher extends Activity
return (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch());
}
- public View getOrCreateQsbBar() {
- if (launcherCallbacksProvidesSearch()) {
- return mLauncherCallbacks.getQsbBar();
- }
-
- if (mQsb == null) {
- AppWidgetProviderInfo searchProvider = Utilities.getSearchWidgetProvider(this);
- if (searchProvider == null) {
- return null;
- }
-
- Bundle opts = new Bundle();
- opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
- AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
-
- // Determine the min and max dimensions of the widget.
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile portraitProfile = app.getInvariantDeviceProfile().portraitProfile;
- DeviceProfile landscapeProfile = app.getInvariantDeviceProfile().landscapeProfile;
- float density = getResources().getDisplayMetrics().density;
- Point searchDimens = portraitProfile.getSearchBarDimensForWidgetOpts(getResources());
- int maxHeight = (int) (searchDimens.y / density);
- int minHeight = maxHeight;
- int maxWidth = (int) (searchDimens.x / density);
- int minWidth = maxWidth;
- if (!landscapeProfile.isVerticalBarLayout()) {
- searchDimens = landscapeProfile.getSearchBarDimensForWidgetOpts(getResources());
- maxHeight = (int) Math.max(maxHeight, searchDimens.y / density);
- minHeight = (int) Math.min(minHeight, searchDimens.y / density);
- maxWidth = (int) Math.max(maxWidth, searchDimens.x / density);
- minWidth = (int) Math.min(minWidth, searchDimens.x / density);
- }
- opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight);
- opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight);
- opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, maxWidth);
- opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, minWidth);
- if (LOGD) {
- Log.d(TAG, "QSB widget options: maxHeight=" + maxHeight + " minHeight=" + minHeight
- + " maxWidth=" + maxWidth + " minWidth=" + minWidth);
- }
-
- if (mLauncherCallbacks != null) {
- opts.putAll(mLauncherCallbacks.getAdditionalSearchWidgetOptions());
- }
-
- int widgetId = mSharedPrefs.getInt(QSB_WIDGET_ID, -1);
- AppWidgetProviderInfo widgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId);
- if (!searchProvider.provider.flattenToString().equals(
- mSharedPrefs.getString(QSB_WIDGET_PROVIDER, null))
- || (widgetInfo == null)
- || !widgetInfo.provider.equals(searchProvider.provider)) {
- // A valid widget is not already bound.
- if (widgetId > -1) {
- mAppWidgetHost.deleteAppWidgetId(widgetId);
- widgetId = -1;
- }
-
- // Try to bind a new widget
- widgetId = mAppWidgetHost.allocateAppWidgetId();
-
- if (!AppWidgetManagerCompat.getInstance(this)
- .bindAppWidgetIdIfAllowed(widgetId, searchProvider, opts)) {
- mAppWidgetHost.deleteAppWidgetId(widgetId);
- widgetId = -1;
- }
-
- mSharedPrefs.edit()
- .putInt(QSB_WIDGET_ID, widgetId)
- .putString(QSB_WIDGET_PROVIDER, searchProvider.provider.flattenToString())
- .apply();
- }
-
- mAppWidgetHost.setQsbWidgetId(widgetId);
- if (widgetId != -1) {
- mQsb = mAppWidgetHost.createView(this, widgetId, searchProvider);
- mQsb.setId(R.id.qsb_widget);
- if (!Utilities.containsAll(
- AppWidgetManager.getInstance(this).getAppWidgetOptions(widgetId), opts)) {
- // Launcher should not be updating the options often.
- FileLog.d(TAG, "Options for QSB were not same");
- mQsb.updateAppWidgetOptions(opts);
- }
- mQsb.setPadding(0, 0, 0, 0);
- mSearchDropTargetBar.addView(mQsb);
- mSearchDropTargetBar.setQsbSearchBar(mQsb);
- }
- }
- return mQsb;
- }
-
- private void reinflateQSBIfNecessary() {
- if (mQsb instanceof LauncherAppWidgetHostView &&
- ((LauncherAppWidgetHostView) mQsb).isReinflateRequired()) {
- mSearchDropTargetBar.removeView(mQsb);
- mQsb = null;
- mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
- }
- }
-
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
final boolean result = super.dispatchPopulateAccessibilityEvent(event);
@@ -3615,16 +3502,6 @@ public class Launcher extends Activity
}
/**
- * Receives notifications when system dialogs are to be closed.
- */
- @Thunk class CloseSystemDialogsIntentReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- closeSystemDialogs();
- }
- }
-
- /**
* If the activity is currently paused, signal that we need to run the passed Runnable
* in onResume.
*
@@ -3729,12 +3606,13 @@ public class Launcher extends Activity
@Override
public void bindScreens(ArrayList<Long> orderedScreenIds) {
- bindAddScreens(orderedScreenIds);
-
- // If there are no screens, we need to have an empty screen
- if (orderedScreenIds.size() == 0) {
- mWorkspace.addExtraEmptyScreen();
+ // Make sure the first screen is always at the start.
+ if (orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != 0) {
+ orderedScreenIds.remove(Workspace.FIRST_SCREEN_ID);
+ orderedScreenIds.add(0, Workspace.FIRST_SCREEN_ID);
+ mModel.updateWorkspaceScreenOrder(this, orderedScreenIds);
}
+ bindAddScreens(orderedScreenIds);
// Create the custom content page (this call updates mDefaultScreen which calls
// setCurrentPage() so ensure that all pages are added before calling this).
@@ -3744,11 +3622,14 @@ public class Launcher extends Activity
}
}
- @Override
- public void bindAddScreens(ArrayList<Long> orderedScreenIds) {
+ private void bindAddScreens(ArrayList<Long> orderedScreenIds) {
int count = orderedScreenIds.size();
for (int i = 0; i < count; i++) {
- mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(orderedScreenIds.get(i));
+ long screenId = orderedScreenIds.get(i);
+ if (screenId != Workspace.FIRST_SCREEN_ID) {
+ // No need to bind the first screen, as its always bound.
+ mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(screenId);
+ }
}
}
@@ -3827,24 +3708,6 @@ public class Launcher extends Activity
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
ShortcutInfo info = (ShortcutInfo) item;
view = createShortcut(info);
-
- /*
- * TODO: FIX collision case
- */
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- CellLayout cl = mWorkspace.getScreenWithId(item.screenId);
- if (cl != null && cl.isOccupied(item.cellX, item.cellY)) {
- View v = cl.getChildAt(item.cellX, item.cellY);
- Object tag = v.getTag();
- String desc = "Collision while binding workspace item: " + item
- + ". Collides with " + tag;
- if (ProviderConfig.IS_DOGFOOD_BUILD) {
- throw (new RuntimeException(desc));
- } else {
- Log.d(TAG, desc);
- }
- }
- }
break;
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
view = FolderIcon.fromXml(R.layout.folder_icon, this,
@@ -3855,6 +3718,25 @@ public class Launcher extends Activity
throw new RuntimeException("Invalid Item Type");
}
+ /*
+ * Remove colliding items.
+ */
+ if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ CellLayout cl = mWorkspace.getScreenWithId(item.screenId);
+ if (cl != null && cl.isOccupied(item.cellX, item.cellY)) {
+ View v = cl.getChildAt(item.cellX, item.cellY);
+ Object tag = v.getTag();
+ String desc = "Collision while binding workspace item: " + item
+ + ". Collides with " + tag;
+ if (ProviderConfig.IS_DOGFOOD_BUILD) {
+ throw (new RuntimeException(desc));
+ } else {
+ Log.d(TAG, desc);
+ LauncherModel.deleteItemFromDatabase(this, item);
+ continue;
+ }
+ }
+ }
workspace.addInScreenFromBind(view, item.container, item.screenId, item.cellX,
item.cellY, 1, 1);
if (animateIcons) {
@@ -4154,17 +4036,6 @@ public class Launcher extends Activity
return LauncherCallbacks.SEARCH_BAR_HEIGHT_NORMAL;
}
- public void bindSearchProviderChanged() {
- if (mSearchDropTargetBar == null) {
- return;
- }
- if (mQsb != null) {
- mSearchDropTargetBar.removeView(mQsb);
- mQsb = null;
- }
- mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
- }
-
/**
* A runnable that we can dequeue and re-enqueue when all applications are bound (to prevent
* multiple calls to bind the same list.)
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 9d889e09a..ae3abbf61 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -105,7 +105,6 @@ public class LauncherAppState {
// Register intent receivers
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
- filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
// For handling managed profiles
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 8c23ff30d..3bb73813d 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -37,7 +37,6 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
private final ArrayList<Runnable> mProviderChangeListeners = new ArrayList<Runnable>();
- private int mQsbWidgetId = -1;
private Launcher mLauncher;
public LauncherAppWidgetHost(Launcher launcher, int hostId) {
@@ -45,23 +44,9 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
mLauncher = launcher;
}
- public void setQsbWidgetId(int widgetId) {
- mQsbWidgetId = widgetId;
- }
-
@Override
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
- if (appWidgetId == mQsbWidgetId) {
- return new LauncherAppWidgetHostView(context) {
-
- @Override
- protected View getErrorView() {
- // For the QSB, show an empty view instead of an error view.
- return new View(getContext());
- }
- };
- }
return new LauncherAppWidgetHostView(context);
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 28557d0a5..53d9c0455 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -54,6 +54,8 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mChildrenFocused;
+ protected int mErrorViewId = R.layout.appwidget_error;
+
public LauncherAppWidgetHostView(Context context) {
super(context);
mContext = context;
@@ -68,7 +70,7 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc
@Override
protected View getErrorView() {
- return mInflater.inflate(R.layout.appwidget_error, this, false);
+ return mInflater.inflate(mErrorViewId, this, false);
}
public void updateLastInflationOrientation() {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 649f42dd1..557a91a42 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import android.app.SearchManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -177,7 +176,6 @@ public class LauncherModel extends BroadcastReceiver
public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,
boolean forceAnimateIcons);
public void bindScreens(ArrayList<Long> orderedScreenIds);
- public void bindAddScreens(ArrayList<Long> orderedScreenIds);
public void finishBindingItems();
public void bindAppWidget(LauncherAppWidgetInfo info);
public void bindAllApplications(ArrayList<AppInfo> apps);
@@ -196,7 +194,6 @@ public class LauncherModel extends BroadcastReceiver
public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos);
public void notifyWidgetProvidersChanged();
public void bindWidgetsModel(WidgetsModel model);
- public void bindSearchProviderChanged();
public boolean isAllAppsButtonRank(int rank);
public void onPageBoundSynchronously(int page);
public void executeOnNextDraw(ViewOnDrawExecutor executor);
@@ -1139,11 +1136,6 @@ public class LauncherModel extends BroadcastReceiver
if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
// If we have changed locale we need to clear out the labels in all apps/workspace.
forceReload();
- } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action)) {
- Callbacks callbacks = getCallback();
- if (callbacks != null) {
- callbacks.bindSearchProviderChanged();
- }
} else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
|| LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
UserManagerCompat.getInstance(context).enableAndResetCache();
@@ -1528,7 +1520,12 @@ public class LauncherModel extends BroadcastReceiver
}
if (!occupied.containsKey(item.screenId)) {
- occupied.put(item.screenId, new GridOccupancy(countX + 1, countY + 1));
+ GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
+ if (item.screenId == Workspace.FIRST_SCREEN_ID) {
+ // Mark the first row as occupied in order to account for the QSB.
+ screen.markCells(0, 0, countX + 1, 1, true);
+ }
+ occupied.put(item.screenId, screen);
}
final GridOccupancy occupancy = occupied.get(item.screenId);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 11d61d02f..49ce06a44 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -611,8 +611,11 @@ public class LauncherProvider extends ContentProvider {
// Database was just created, so wipe any previous widgets
if (mWidgetHostResetHandler != null) {
new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID).deleteHost();
- mWidgetHostResetHandler.sendEmptyMessage(
- ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET);
+ mWidgetHostResetHandler.sendMessage(Message.obtain(
+ mWidgetHostResetHandler,
+ ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET,
+ mContext
+ ));
}
// Set the flag for empty DB
@@ -1100,7 +1103,11 @@ public class LauncherProvider extends ContentProvider {
mListener.onExtractedColorsChanged();
break;
case MSG_APP_WIDGET_HOST_RESET:
- mListener.onAppWidgetHostReset();
+ Context context = (Context) msg.obj;
+ if (context != null) {
+ context.sendBroadcast(new Intent(Launcher.ACTION_APPWIDGET_HOST_RESET)
+ .setPackage(context.getPackageName()));
+ }
break;
}
}
diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java
index 524befc58..5998dadcd 100644
--- a/src/com/android/launcher3/LauncherProviderChangeListener.java
+++ b/src/com/android/launcher3/LauncherProviderChangeListener.java
@@ -10,6 +10,4 @@ public interface LauncherProviderChangeListener {
public void onLauncherProviderChange();
public void onExtractedColorsChanged();
-
- public void onAppWidgetHostReset();
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index fdca9f2fe..4af53d279 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1653,7 +1653,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
final int pageUnderPointIndex = getNearestHoverOverPageIndex();
- if (pageUnderPointIndex > -1 && pageUnderPointIndex != indexOfChild(mDragView)) {
+ // Do not allow any page to be moved to 0th position.
+ if (pageUnderPointIndex > 0 && pageUnderPointIndex != indexOfChild(mDragView)) {
mTempVisiblePagesRange[0] = 0;
mTempVisiblePagesRange[1] = getPageCount() - 1;
getFreeScrollPageRange(mTempVisiblePagesRange);
@@ -2171,7 +2172,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
public boolean startReordering(View v) {
int dragViewIndex = indexOfChild(v);
- if (mTouchState != TOUCH_STATE_REST || dragViewIndex == -1) return false;
+ // Do not allow the first page to be moved around
+ if (mTouchState != TOUCH_STATE_REST || dragViewIndex <= 0) return false;
mTempVisiblePagesRange[0] = 0;
mTempVisiblePagesRange[1] = getPageCount() - 1;
diff --git a/src/com/android/launcher3/PinchAnimationManager.java b/src/com/android/launcher3/PinchAnimationManager.java
index c8c8fa4c8..c1c25195b 100644
--- a/src/com/android/launcher3/PinchAnimationManager.java
+++ b/src/com/android/launcher3/PinchAnimationManager.java
@@ -150,12 +150,10 @@ public class PinchAnimationManager {
animateOverviewPanelButtons(goingTowards == OVERVIEW);
} else if (startState == NORMAL) {
animateHotseatAndPageIndicator(goingTowards == NORMAL);
- animateQsb(goingTowards == NORMAL);
}
} else if (threshold == PinchThresholdManager.THRESHOLD_TWO) {
if (startState == OVERVIEW) {
animateHotseatAndPageIndicator(goingTowards == NORMAL);
- animateQsb(goingTowards == NORMAL);
animateScrim(goingTowards == OVERVIEW);
} else if (startState == NORMAL) {
animateOverviewPanelButtons(goingTowards == OVERVIEW);
@@ -198,12 +196,6 @@ public class PinchAnimationManager {
}
}
- private void animateQsb(boolean show) {
- SearchDropTargetBar.State searchBarState = show ? SearchDropTargetBar.State.SEARCH_BAR
- : SearchDropTargetBar.State.INVISIBLE;
- mLauncher.getSearchDropTargetBar().animateToState(searchBarState, THRESHOLD_ANIM_DURATION);
- }
-
private void animateOverviewPanelButtons(boolean show) {
animateShowHideView(INDEX_OVERVIEW_PANEL_BUTTONS, mLauncher.getOverviewPanel(), show);
}
diff --git a/src/com/android/launcher3/QsbContainerView.java b/src/com/android/launcher3/QsbContainerView.java
new file mode 100644
index 000000000..0a112d23e
--- /dev/null
+++ b/src/com/android/launcher3/QsbContainerView.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2016 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;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.SearchManager;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
+/**
+ * A frame layout which contains a QSB. This internally uses fragment to bind the view, which
+ * allows it to contain the logic for {@link Fragment#startActivityForResult(Intent, int)}.
+ */
+public class QsbContainerView extends FrameLayout {
+
+ private boolean mBound;
+
+ public QsbContainerView(Context context) {
+ super(context);
+ }
+
+ public QsbContainerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public QsbContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (!mBound) {
+ FragmentManager fm = ((Launcher) getContext()).getFragmentManager();
+ fm.beginTransaction().add(R.id.qsb_container, new QsbFragment()).commit();
+ mBound = true;
+ }
+ }
+
+ @Override
+ public void setPadding(int left, int top, int right, int bottom) {
+ super.setPadding(0, 0, 0, 0);
+ }
+
+ /**
+ * A fragment to display the QSB.
+ */
+ public static class QsbFragment extends Fragment implements View.OnClickListener {
+
+ private static final int REQUEST_BIND_QSB = 1;
+ private static final String QSB_WIDGET_ID = "qsb_widget_id";
+
+ private static int sSavedWidgetId = -1;
+
+ private AppWidgetProviderInfo mWidgetInfo;
+ private LauncherAppWidgetHostView mQsb;
+
+ private BroadcastReceiver mRebindReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ rebindFragment();
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ IntentFilter filter = new IntentFilter(Launcher.ACTION_APPWIDGET_HOST_RESET);
+ filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
+ getContext().registerReceiver(mRebindReceiver, filter);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+ if (savedInstanceState != null) {
+ sSavedWidgetId = savedInstanceState.getInt(QSB_WIDGET_ID, -1);
+ }
+
+ Launcher launcher = (Launcher) getActivity();
+ mWidgetInfo = getSearchWidgetProvider(launcher);
+ if (mWidgetInfo == null) {
+ // There is no search provider, just show the default widget.
+ return getDefaultView(inflater, container, false);
+ }
+
+ SharedPreferences prefs = Utilities.getPrefs(launcher);
+ AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(launcher);
+ LauncherAppWidgetHost widgetHost = launcher.getAppWidgetHost();
+ InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
+
+ Bundle opts = new Bundle();
+ Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(launcher, idp.numColumns, 1, null);
+ opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
+ opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top);
+ opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right);
+ opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom);
+
+ int widgetId = prefs.getInt(QSB_WIDGET_ID, -1);
+ AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId);
+ boolean isWidgetBound = (widgetInfo != null) &&
+ widgetInfo.provider.equals(mWidgetInfo.provider);
+
+ if (!isWidgetBound) {
+ // widgetId is already bound and its not the correct provider.
+ // Delete the widget id.
+ if (widgetId > -1) {
+ widgetHost.deleteAppWidgetId(widgetId);
+ widgetId = -1;
+ }
+
+ widgetId = widgetHost.allocateAppWidgetId();
+ isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(widgetId, mWidgetInfo, opts);
+ if (!isWidgetBound) {
+ widgetHost.deleteAppWidgetId(widgetId);
+ widgetId = -1;
+ }
+ }
+
+ if (isWidgetBound) {
+ mQsb = (LauncherAppWidgetHostView)
+ widgetHost.createView(launcher, widgetId, mWidgetInfo);
+ mQsb.setId(R.id.qsb_widget);
+ mQsb.mErrorViewId = R.layout.qsb_default_view;
+
+ if (!Utilities.containsAll(AppWidgetManager.getInstance(launcher)
+ .getAppWidgetOptions(widgetId), opts)) {
+ mQsb.updateAppWidgetOptions(opts);
+ }
+ mQsb.setPadding(0, 0, 0, 0);
+ return mQsb;
+ }
+
+ // Return a default widget with setup icon.
+ return getDefaultView(inflater, container, true);
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view.getId() == R.id.btn_qsb_search) {
+ getActivity().startSearch("", false, null, true);
+ } else if (view.getId() == R.id.btn_qsb_setup) {
+ // Allocate a new widget id for QSB
+ sSavedWidgetId = ((Launcher) getActivity())
+ .getAppWidgetHost().allocateAppWidgetId();
+ // Start intent for bind the widget
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, sSavedWidgetId);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mWidgetInfo.provider);
+ startActivityForResult(intent, REQUEST_BIND_QSB);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(QSB_WIDGET_ID, sSavedWidgetId);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_BIND_QSB) {
+ if (resultCode == Activity.RESULT_OK) {
+ int widgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ sSavedWidgetId);
+ Utilities.getPrefs(getContext()).edit().putInt(QSB_WIDGET_ID, widgetId).apply();
+ sSavedWidgetId = -1;
+ rebindFragment();
+ } else if (sSavedWidgetId != -1) {
+ ((Launcher) getActivity()).getAppWidgetHost().deleteAppWidgetId(sSavedWidgetId);
+ sSavedWidgetId = -1;
+ }
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mQsb != null && mQsb.isReinflateRequired()) {
+ rebindFragment();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ getContext().unregisterReceiver(mRebindReceiver);
+ super.onDestroy();
+ }
+
+ private void rebindFragment() {
+ if (getActivity() != null) {
+ // Recreate the fragment. This will cause the qsb to be inflated again.
+ getActivity().getFragmentManager().beginTransaction()
+ .replace(R.id.qsb_container, new QsbFragment()).commit();
+ }
+ }
+
+ private View getDefaultView(LayoutInflater inflater, ViewGroup parent, boolean showSetup) {
+ View v = inflater.inflate(R.layout.qsb_default_view, parent, false);
+ if (showSetup) {
+ View setupButton = v.findViewById(R.id.btn_qsb_setup);
+ setupButton.setVisibility(View.VISIBLE);
+ setupButton.setOnClickListener(this);
+ }
+ v.findViewById(R.id.btn_qsb_search).setOnClickListener(this);
+ return v;
+ }
+ }
+
+ /**
+ * Returns a widget with category {@link AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}
+ * provided by the same package which is set to be global search activity.
+ * If widgetCategory is not supported, or no such widget is found, returns the first widget
+ * provided by the package.
+ */
+ public static AppWidgetProviderInfo getSearchWidgetProvider(Context context) {
+ SearchManager searchManager =
+ (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
+ ComponentName searchComponent = searchManager.getGlobalSearchActivity();
+ if (searchComponent == null) return null;
+ String providerPkg = searchComponent.getPackageName();
+
+ AppWidgetProviderInfo defaultWidgetForSearchPackage = null;
+
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
+ for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) {
+ if (info.provider.getPackageName().equals(providerPkg) && info.configure == null) {
+ if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) != 0) {
+ return info;
+ } else if (defaultWidgetForSearchPackage == null) {
+ defaultWidgetForSearchPackage = info;
+ }
+ }
+ }
+ return defaultWidgetForSearchPackage;
+ }
+}
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
index 171dd8771..e43e96c76 100644
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ b/src/com/android/launcher3/SearchDropTargetBar.java
@@ -16,8 +16,6 @@
package com.android.launcher3;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
@@ -26,8 +24,6 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewDebug;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import com.android.launcher3.dragndrop.DragController;
@@ -39,32 +35,21 @@ import com.android.launcher3.util.Thunk;
*/
public class SearchDropTargetBar extends BaseDropTargetBar {
- private static final TimeInterpolator MOVE_DOWN_INTERPOLATOR = new DecelerateInterpolator(0.6f);
- private static final TimeInterpolator MOVE_UP_INTERPOLATOR = new DecelerateInterpolator(1.5f);
-
/** The different states that the search bar space can be in. */
public enum State {
- INVISIBLE (0f, 0f, 0f),
- INVISIBLE_TRANSLATED (0f, 0f, -1f),
- SEARCH_BAR (1f, 0f, 0f),
- DROP_TARGET (0f, 1f, 0f);
+ INVISIBLE (0f),
+ DROP_TARGET (1f);
- private final float mSearchBarAlpha;
private final float mDropTargetBarAlpha;
- private final float mTranslation;
- State(float sbAlpha, float dtbAlpha, float translation) {
- mSearchBarAlpha = sbAlpha;
+ State(float dtbAlpha) {
mDropTargetBarAlpha = dtbAlpha;
- mTranslation = translation;
}
-
}
@ViewDebug.ExportedProperty(category = "launcher")
- private State mState = State.SEARCH_BAR;
- @Thunk View mQSB;
+ private State mState = State.INVISIBLE;
// Drop targets
private ButtonDropTarget mDeleteDropTarget;
@@ -113,11 +98,7 @@ public class SearchDropTargetBar extends BaseDropTargetBar {
@Override
public void hideDropTargets() {
- animateToState(State.SEARCH_BAR, DEFAULT_DRAG_FADE_DURATION);
- }
-
- public void setQsbSearchBar(View qsb) {
- mQSB = qsb;
+ animateToState(State.INVISIBLE, DEFAULT_DRAG_FADE_DURATION);
}
/**
@@ -140,30 +121,6 @@ public class SearchDropTargetBar extends BaseDropTargetBar {
AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled);
}
- if (mQSB != null) {
- boolean isVertical = ((Launcher) getContext()).getDeviceProfile()
- .isVerticalBarLayout();
- float translation = isVertical ? 0 : mState.mTranslation * getMeasuredHeight();
-
- if (duration > 0) {
- int translationChange = Float.compare(mQSB.getTranslationY(), translation);
-
- animateAlpha(mQSB, mState.mSearchBarAlpha,
- translationChange == 0 ? DEFAULT_INTERPOLATOR
- : (translationChange < 0 ? MOVE_DOWN_INTERPOLATOR
- : MOVE_UP_INTERPOLATOR));
-
- if (translationChange != 0) {
- mCurrentAnimation.play(
- ObjectAnimator.ofFloat(mQSB, View.TRANSLATION_Y, translation));
- }
- } else {
- mQSB.setTranslationY(translation);
- mQSB.setAlpha(mState.mSearchBarAlpha);
- AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled);
- }
- }
-
// Start the final animation
if (duration > 0) {
if (animation != null) {
@@ -175,30 +132,8 @@ public class SearchDropTargetBar extends BaseDropTargetBar {
}
}
- /**
- * @return the bounds of the QSB search bar.
- */
- public Rect getSearchBarBounds() {
- if (mQSB != null) {
- final int[] pos = new int[2];
- mQSB.getLocationOnScreen(pos);
-
- final Rect rect = new Rect();
- rect.left = pos[0];
- rect.top = pos[1];
- rect.right = pos[0] + mQSB.getWidth();
- rect.bottom = pos[1] + mQSB.getHeight();
- return rect;
- } else {
- return null;
- }
- }
-
@Override
public void enableAccessibleDrag(boolean enable) {
- if (mQSB != null) {
- mQSB.setVisibility(enable ? View.GONE : View.VISIBLE);
- }
mDeleteDropTarget.enableAccessibleDrag(enable);
mUninstallDropTarget.enableAccessibleDrag(enable);
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index c9d8cce84..4aaa02fd3 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -18,10 +18,7 @@ package com.android.launcher3;
import android.annotation.TargetApi;
import android.app.Activity;
-import android.app.SearchManager;
import android.app.WallpaperManager;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -603,39 +600,6 @@ public final class Utilities {
}
/**
- * Returns a widget with category {@link AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}
- * provided by the same package which is set to be global search activity.
- * If widgetCategory is not supported, or no such widget is found, returns the first widget
- * provided by the package.
- */
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- public static AppWidgetProviderInfo getSearchWidgetProvider(Context context) {
- SearchManager searchManager =
- (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
- ComponentName searchComponent = searchManager.getGlobalSearchActivity();
- if (searchComponent == null) return null;
- String providerPkg = searchComponent.getPackageName();
-
- AppWidgetProviderInfo defaultWidgetForSearchPackage = null;
-
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
- for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) {
- if (info.provider.getPackageName().equals(providerPkg)) {
- if (ATLEAST_JB_MR1) {
- if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) != 0) {
- return info;
- } else if (defaultWidgetForSearchPackage == null) {
- defaultWidgetForSearchPackage = info;
- }
- } else {
- return info;
- }
- }
- }
- return defaultWidgetForSearchPackage;
- }
-
- /**
* Compresses the bitmap to a byte array for serialization.
*/
public static byte[] flattenBitmap(Bitmap bitmap) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0f0673a91..6f81f59cf 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -73,7 +73,6 @@ import com.android.launcher3.dragndrop.SpringLoadedDragController;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.logging.UserEventDispatcher;
-import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.LongArrayMap;
@@ -109,7 +108,10 @@ public class Workspace extends PagedView
private static final boolean MAP_RECURSE = true;
// The screen id used for the empty screen always present to the right.
- public final static long EXTRA_EMPTY_SCREEN_ID = -201;
+ public static final long EXTRA_EMPTY_SCREEN_ID = -201;
+ // The is the first screen. It is always present, even if its empty.
+ public static final long FIRST_SCREEN_ID = 0;
+
private final static long CUSTOM_CONTENT_SCREEN_ID = -301;
private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;
@@ -180,8 +182,8 @@ public class Workspace extends PagedView
// in all apps or customize mode)
enum State {
- NORMAL (SearchDropTargetBar.State.SEARCH_BAR, false, false),
- NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE_TRANSLATED, false, false),
+ NORMAL (SearchDropTargetBar.State.INVISIBLE, false, false),
+ NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE, false, false),
SPRING_LOADED (SearchDropTargetBar.State.DROP_TARGET, false, true),
OVERVIEW (SearchDropTargetBar.State.INVISIBLE, true, true),
OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE, true, false);
@@ -501,6 +503,32 @@ public class Workspace extends PagedView
return mTouchState != TOUCH_STATE_REST;
}
+ /**
+ * Initializes and binds the first page
+ * @param qsb an exisitng qsb to recycle or null.
+ */
+ public void bindAndInitFirstWorkspaceScreen(View qsb) {
+ // Add the first page
+ CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
+
+ if (qsb == null) {
+ // Always add a QSB on the first screen.
+ qsb = mLauncher.getLayoutInflater().inflate(R.layout.qsb_container,
+ firstPage, false);
+ }
+
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) qsb.getLayoutParams();
+ lp.cellX = 0;
+ lp.cellY = 0;
+ lp.cellHSpan = firstPage.getCountX();
+ lp.cellVSpan = 1;
+ lp.canReorder = false;
+
+ if (!firstPage.addViewToCellLayout(qsb, 0, R.id.qsb_container, lp, true)) {
+ Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout");
+ }
+ }
+
public void removeAllWorkspaceScreens() {
// Disable all layout transitions before removing all pages to ensure that we don't get the
// transition animations competing with us changing the scroll when we add pages or the
@@ -513,30 +541,39 @@ public class Workspace extends PagedView
removeCustomContentPage();
}
+ // Recycle the QSB widget
+ View qsb = findViewById(R.id.qsb_container);
+ if (qsb != null) {
+ ((ViewGroup) qsb.getParent()).removeView(qsb);
+ }
+
// Remove the pages and clear the screen models
removeAllViews();
mScreenOrder.clear();
mWorkspaceScreens.clear();
+ // Ensure that the first page is always present
+ bindAndInitFirstWorkspaceScreen(qsb);
+
// Re-enable the layout transitions
enableLayoutTransitions();
}
- public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {
+ public void insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {
// Find the index to insert this view into. If the empty screen exists, then
// insert it before that.
int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
if (insertIndex < 0) {
insertIndex = mScreenOrder.size();
}
- return insertNewWorkspaceScreen(screenId, insertIndex);
+ insertNewWorkspaceScreen(screenId, insertIndex);
}
- public long insertNewWorkspaceScreen(long screenId) {
- return insertNewWorkspaceScreen(screenId, getChildCount());
+ public void insertNewWorkspaceScreen(long screenId) {
+ insertNewWorkspaceScreen(screenId, getChildCount());
}
- public long insertNewWorkspaceScreen(long screenId, int insertIndex) {
+ public CellLayout insertNewWorkspaceScreen(long screenId, int insertIndex) {
if (mWorkspaceScreens.containsKey(screenId)) {
throw new RuntimeException("Screen id " + screenId + " already exists!");
}
@@ -558,7 +595,8 @@ public class Workspace extends PagedView
if (delegate != null && delegate.isInAccessibleDrag()) {
newScreen.enableAccessibleDrag(true, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
}
- return screenId;
+
+ return newScreen;
}
public void createCustomContentContainer() {
@@ -860,7 +898,8 @@ public class Workspace extends PagedView
for (int i = 0; i < total; i++) {
long id = mWorkspaceScreens.keyAt(i);
CellLayout cl = mWorkspaceScreens.valueAt(i);
- if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {
+ // FIRST_SCREEN_ID can never be removed.
+ if (id > FIRST_SCREEN_ID && cl.getShortcutsAndWidgets().getChildCount() == 0) {
removeScreens.add(id);
}
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index f900790bb..dd11bde6d 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -22,6 +22,7 @@ import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
import com.android.launcher3.backup.nano.BackupProtos;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
@@ -221,7 +222,7 @@ public class GridSizeMigrationTask {
// {@link #mCarryOver}, to prevent an infinite loop. If no item could be removed,
// break the loop and abort migration by throwing an exception.
OptimalPlacementSolution placement = new OptimalPlacementSolution(
- new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), true);
+ new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), 0, true);
placement.find();
if (placement.finalPlacedItems.size() > 0) {
long newScreenId = LauncherSettings.Settings.call(
@@ -262,13 +263,16 @@ public class GridSizeMigrationTask {
* Migrate a particular screen id.
* Strategy:
* 1) For all possible combinations of row and column, pick the one which causes the least
- * data loss: {@link #tryRemove(int, int, ArrayList, float[])}
+ * data loss: {@link #tryRemove(int, int, int, ArrayList, float[])}
* 2) Maintain a list of all lost items before this screen, and add any new item lost from
* this screen to that list as well.
* 3) If all those items from the above list can be placed on this screen, place them
* (otherwise they are placed on a new screen).
*/
private void migrateScreen(long screenId) {
+ // If we are migrating the first screen, do not touch the first row.
+ int startY = screenId == Workspace.FIRST_SCREEN_ID ? 1 : 0;
+
ArrayList<DbEntry> items = loadWorkspaceEntries(screenId);
int removedCol = Integer.MAX_VALUE;
@@ -286,10 +290,10 @@ public class GridSizeMigrationTask {
// Try removing all possible combinations
for (int x = 0; x < mSrcX; x++) {
- for (int y = 0; y < mSrcY; y++) {
+ for (int y = startY; y < mSrcY; y++) {
// Use a deep copy when trying out a particular combination as it can change
// the underlying object.
- ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, deepCopy(items), outLoss);
+ ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items), outLoss);
if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1] < moveWt))) {
removeWt = outLoss[0];
@@ -338,12 +342,13 @@ public class GridSizeMigrationTask {
if (!mCarryOver.isEmpty() && removeWt == 0) {
// No new items were removed in this step. Try placing all the items on this screen.
GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
+ occupied.markCells(0, 0, mTrgX, startY, true);
for (DbEntry item : finalItems) {
occupied.markCells(item, true);
}
OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied,
- deepCopy(mCarryOver), true);
+ deepCopy(mCarryOver), startY, true);
placement.find();
if (placement.lowestWeightLoss == 0) {
// All items got placed
@@ -375,9 +380,10 @@ public class GridSizeMigrationTask {
* @param outLoss array of size 2. The first entry is filled with weight loss, and the second
* with the overall item movement.
*/
- private ArrayList<DbEntry> tryRemove(int col, int row, ArrayList<DbEntry> items,
- float[] outLoss) {
+ private ArrayList<DbEntry> tryRemove(int col, int row, int startY,
+ ArrayList<DbEntry> items, float[] outLoss) {
GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
+ occupied.markCells(0, 0, mTrgX, startY, true);
col = mShouldRemoveX ? col : Integer.MAX_VALUE;
row = mShouldRemoveY ? row : Integer.MAX_VALUE;
@@ -399,7 +405,8 @@ public class GridSizeMigrationTask {
}
}
- OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied, removedItems);
+ OptimalPlacementSolution placement =
+ new OptimalPlacementSolution(occupied, removedItems, startY);
placement.find();
finalItems.addAll(placement.finalPlacedItems);
outLoss[0] = placement.lowestWeightLoss;
@@ -415,19 +422,24 @@ public class GridSizeMigrationTask {
// linear placement.
private final boolean ignoreMove;
+ // The first row in the grid from where the placement should start.
+ private final int startY;
+
float lowestWeightLoss = Float.MAX_VALUE;
float lowestMoveCost = Float.MAX_VALUE;
ArrayList<DbEntry> finalPlacedItems;
- public OptimalPlacementSolution(GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace) {
- this(occupied, itemsToPlace, false);
+ public OptimalPlacementSolution(
+ GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace, int startY) {
+ this(occupied, itemsToPlace, startY, false);
}
public OptimalPlacementSolution(GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace,
- boolean ignoreMove) {
+ int startY, boolean ignoreMove) {
this.occupied = occupied;
this.itemsToPlace = itemsToPlace;
this.ignoreMove = ignoreMove;
+ this.startY = startY;
// Sort the items such that larger widgets appear first followed by 1x1 items
Collections.sort(this.itemsToPlace);
@@ -477,7 +489,7 @@ public class GridSizeMigrationTask {
int myW = me.spanX;
int myH = me.spanY;
- for (int y = 0; y < mTrgY; y++) {
+ for (int y = startY; y < mTrgY; y++) {
for (int x = 0; x < mTrgX; x++) {
float newMoveCost = moveCost;
if (x != myX) {
@@ -547,7 +559,7 @@ public class GridSizeMigrationTask {
int newDistance = Integer.MAX_VALUE;
int newX = Integer.MAX_VALUE, newY = Integer.MAX_VALUE;
- for (int y = 0; y < mTrgY; y++) {
+ for (int y = startY; y < mTrgY; y++) {
for (int x = 0; x < mTrgX; x++) {
if (!occupied.cells[x][y]) {
int dist = ignoreMove ? 0 :
diff --git a/src/com/android/launcher3/util/GridOccupancy.java b/src/com/android/launcher3/util/GridOccupancy.java
index 3f5f0b4ed..6a10b0aa5 100644
--- a/src/com/android/launcher3/util/GridOccupancy.java
+++ b/src/com/android/launcher3/util/GridOccupancy.java
@@ -77,7 +77,7 @@ public class GridOccupancy {
public void markCells(int cellX, int cellY, int spanX, int spanY, boolean value) {
if (cellX < 0 || cellY < 0) return;
for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
- for (int y = cellY; y < cellY + spanY && y < mCountX; y++) {
+ for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
cells[x][y] = value;
}
}