diff options
author | Jon Miranda <jonmiranda@google.com> | 2017-08-22 13:42:47 -0400 |
---|---|---|
committer | Jon Miranda <jonmiranda@google.com> | 2017-08-22 13:52:19 -0400 |
commit | dff92fe1aa90dfad1cce228ee140a70ab7a365b2 (patch) | |
tree | d079f20d40107acf9056d049817318e85ec44bbb /src/com/android | |
parent | 9623a6f891a31f1285f360baf77beb335613e7f5 (diff) | |
parent | 78356a542e14ad6eefd5288506d1e53f601257f6 (diff) | |
download | android_packages_apps_Trebuchet-dff92fe1aa90dfad1cce228ee140a70ab7a365b2.tar.gz android_packages_apps_Trebuchet-dff92fe1aa90dfad1cce228ee140a70ab7a365b2.tar.bz2 android_packages_apps_Trebuchet-dff92fe1aa90dfad1cce228ee140a70ab7a365b2.zip |
merged ub-launcher3-dorval-polish2, and resolved conflicts
Conflicts:
res/values-be/strings.xml
res/values-et/strings.xml
res/values-ms/strings.xml
Bug: 64937210
Test: flashed img
Change-Id: I28557d652cc5a547f8b94a60a41f381a5af2fa84
Diffstat (limited to 'src/com/android')
44 files changed, 769 insertions, 560 deletions
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java index c55a5860e..82175b721 100644 --- a/src/com/android/launcher3/BaseContainerView.java +++ b/src/com/android/launcher3/BaseContainerView.java @@ -62,7 +62,7 @@ public abstract class BaseContainerView extends FrameLayout public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) { + if (this instanceof AllAppsContainerView) { mBaseDrawable = new ColorDrawable(); } else { TypedArray a = context.obtainStyledAttributes(attrs, diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index aeb82b376..a63767c5d 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -592,6 +592,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver { mIconLoadRequest = null; mDisableRelayout = true; + // Optimization: Starting in N, pre-uploads the bitmap to RenderThread. + info.iconBitmap.prepareToDraw(); + if (info instanceof AppInfo) { applyFromApplicationInfo((AppInfo) info); } else if (info instanceof ShortcutInfo) { diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index aac80052e..3ebccda9e 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -780,7 +780,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { return mCellWidth; } - int getCellHeight() { + public int getCellHeight() { return mCellHeight; } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 031bfe115..150bc5309 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -63,7 +63,7 @@ public class DeviceProfile { */ private static final float MAX_HORIZONTAL_PADDING_PERCENT = 0.14f; - private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 1.82f; + private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 2.0f; // Overview mode private final int overviewModeMinIconZoneHeightPx; @@ -75,6 +75,7 @@ public class DeviceProfile { // Workspace private final int desiredWorkspaceLeftRightMarginPx; public final int cellLayoutPaddingLeftRightPx; + public final int cellLayoutBottomPaddingPx; public final int edgeMarginPx; public final Rect defaultWidgetPadding; private final int defaultPageSpacingPx; @@ -84,7 +85,8 @@ public class DeviceProfile { // Page indicator private int pageIndicatorSizePx; - private final int pageIndicatorLandGutterPx; + private final int pageIndicatorLandLeftNavBarGutterPx; + private final int pageIndicatorLandRightNavBarGutterPx; private final int pageIndicatorLandWorkspaceOffsetPx; // Workspace icons @@ -113,13 +115,16 @@ public class DeviceProfile { // Hotseat public int hotseatCellHeightPx; - public int hotseatBarHeightPx; + // In portrait: size = height, in landscape: size = width + public int hotseatBarSizePx; public int hotseatBarTopPaddingPx; + public int hotseatBarBottomPaddingPx; + + public int hotseatBarLeftNavBarLeftPaddingPx; public int hotseatBarLeftNavBarRightPaddingPx; + + public int hotseatBarRightNavBarLeftPaddingPx; public int hotseatBarRightNavBarRightPaddingPx; - public int hotseatBarBottomPaddingPx; - public int hotseatLandLeftNavBarGutterPx; - public int hotseatLandRightNavBarGutterPx; // All apps public int allAppsCellHeightPx; @@ -177,10 +182,14 @@ public class DeviceProfile { desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx; cellLayoutPaddingLeftRightPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding); + cellLayoutBottomPaddingPx = + res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_bottom_padding); pageIndicatorSizePx = res.getDimensionPixelSize( R.dimen.dynamic_grid_min_page_indicator_size); - pageIndicatorLandGutterPx = res.getDimensionPixelSize( - R.dimen.dynamic_grid_page_indicator_gutter_width); + pageIndicatorLandLeftNavBarGutterPx = res.getDimensionPixelSize( + R.dimen.dynamic_grid_page_indicator_land_left_nav_bar_gutter_width); + pageIndicatorLandRightNavBarGutterPx = res.getDimensionPixelSize( + R.dimen.dynamic_grid_page_indicator_land_right_nav_bar_gutter_width); pageIndicatorLandWorkspaceOffsetPx = res.getDimensionPixelSize(R.dimen.all_apps_caret_workspace_offset); defaultPageSpacingPx = @@ -213,16 +222,15 @@ public class DeviceProfile { R.dimen.dynamic_grid_hotseat_land_left_nav_bar_right_padding); hotseatBarRightNavBarRightPaddingPx = res.getDimensionPixelSize( R.dimen.dynamic_grid_hotseat_land_right_nav_bar_right_padding); - hotseatBarHeightPx = isVerticalBarLayout() - ? res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height) - : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height) + hotseatBarLeftNavBarLeftPaddingPx = res.getDimensionPixelSize( + R.dimen.dynamic_grid_hotseat_land_left_nav_bar_left_padding); + hotseatBarRightNavBarLeftPaddingPx = res.getDimensionPixelSize( + R.dimen.dynamic_grid_hotseat_land_right_nav_bar_left_padding); + hotseatBarSizePx = isVerticalBarLayout() + ? Utilities.pxFromDp(inv.iconSize, dm) + : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_size) + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx; - hotseatLandLeftNavBarGutterPx = res.getDimensionPixelSize( - R.dimen.dynamic_grid_hotseat_land_left_nav_bar_gutter_width); - hotseatLandRightNavBarGutterPx = res.getDimensionPixelSize( - R.dimen.dynamic_grid_hotseat_land_right_nav_bar_gutter_width); - // Determine sizes. widthPx = width; heightPx = height; @@ -238,17 +246,17 @@ public class DeviceProfile { updateAvailableDimensions(dm, res); // Now that we have all of the variables calculated, we can tune certain sizes. - float aspectRatio = ((float) Math.max(availableWidthPx, availableHeightPx)) - / Math.min(availableWidthPx, availableHeightPx); + float aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx); boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0; if (!isVerticalBarLayout() && isPhone && isTallDevice) { - // We increase the page indicator size when there is extra space. + // We increase the hotseat size when there is extra space. // ie. For a display with a large aspect ratio, we can keep the icons on the workspace - // in portrait mode closer together by increasing the page indicator size. + // in portrait mode closer together by adding more height to the hotseat. // Note: This calculation was created after noticing a pattern in the design spec. - pageIndicatorSizePx = getCellSize().y - iconSizePx - iconDrawablePaddingPx; + int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx; + hotseatBarSizePx += extraSpace - pageIndicatorSizePx; - // Recalculate the available dimensions using the new page indicator size. + // Recalculate the available dimensions using the new hotseat size. updateAvailableDimensions(dm, res); } @@ -301,10 +309,10 @@ public class DeviceProfile { // In normal cases, All Apps cell height should equal the Workspace cell height. // Since we are removing labels from the Workspace, we need to manually compute the // All Apps cell height. + int topBottomPadding = allAppsIconDrawablePaddingPx * (isVerticalBarLayout() ? 2 : 1); allAppsCellHeightPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx + Utilities.calculateTextHeight(allAppsIconTextSizePx) - // Top and bottom padding is equal to the drawable padding - + allAppsIconDrawablePaddingPx * 2; + + topBottomPadding * 2; } /** @@ -332,11 +340,16 @@ public class DeviceProfile { } private void updateIconSize(float scale, Resources res, DisplayMetrics dm) { + // Workspace float invIconSizePx = isVerticalBarLayout() ? inv.landscapeIconSize : inv.iconSize; iconSizePx = (int) (Utilities.pxFromDp(invIconSizePx, dm) * scale); iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale); iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale); + cellWidthPx = iconSizePx + iconDrawablePaddingPx; + cellHeightPx = iconSizePx + iconDrawablePaddingPx + + Utilities.calculateTextHeight(iconTextSizePx); + // All apps allAppsIconTextSizePx = iconTextSizePx; allAppsIconSizePx = iconSizePx; @@ -348,15 +361,14 @@ public class DeviceProfile { adjustToHideWorkspaceLabels(); } - cellWidthPx = iconSizePx + iconDrawablePaddingPx; - cellHeightPx = iconSizePx + iconDrawablePaddingPx - + Utilities.calculateTextHeight(iconTextSizePx); - // Hotseat - hotseatCellHeightPx = iconSizePx + iconDrawablePaddingPx; + if (isVerticalBarLayout()) { + hotseatBarSizePx = iconSizePx; + } + hotseatCellHeightPx = iconSizePx; if (!isVerticalBarLayout()) { - int expectedWorkspaceHeight = availableHeightPx - hotseatBarHeightPx + int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx - pageIndicatorSizePx - topWorkspacePadding; float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace; workspaceSpringLoadShrinkFactor = Math.min( @@ -449,9 +461,10 @@ public class DeviceProfile { // Since we are only concerned with the overall padding, layout direction does // not matter. Point padding = getTotalWorkspacePadding(); - int cellPadding = cellLayoutPaddingLeftRightPx * 2; - result.x = calculateCellWidth(availableWidthPx - padding.x - cellPadding, inv.numColumns); - result.y = calculateCellHeight(availableHeightPx - padding.y, inv.numRows); + result.x = calculateCellWidth(availableWidthPx - padding.x + - cellLayoutPaddingLeftRightPx * 2, inv.numColumns); + result.y = calculateCellHeight(availableHeightPx - padding.y + - cellLayoutBottomPaddingPx, inv.numRows); return result; } @@ -467,20 +480,21 @@ public class DeviceProfile { Rect padding = recycle == null ? new Rect() : recycle; if (isVerticalBarLayout()) { if (mInsets.left > 0) { - padding.set(mInsets.left + pageIndicatorLandGutterPx, + padding.set(mInsets.left + pageIndicatorLandLeftNavBarGutterPx, 0, - hotseatBarHeightPx + hotseatLandLeftNavBarGutterPx - + hotseatBarLeftNavBarRightPaddingPx - mInsets.left, + hotseatBarSizePx + hotseatBarLeftNavBarRightPaddingPx + + hotseatBarLeftNavBarLeftPaddingPx + - mInsets.left, edgeMarginPx); } else { - padding.set(pageIndicatorLandGutterPx, + padding.set(pageIndicatorLandRightNavBarGutterPx, 0, - hotseatBarHeightPx + hotseatLandRightNavBarGutterPx - + hotseatBarRightNavBarRightPaddingPx, + hotseatBarSizePx + hotseatBarRightNavBarRightPaddingPx + + hotseatBarRightNavBarLeftPaddingPx, edgeMarginPx); } } else { - int paddingBottom = hotseatBarHeightPx + pageIndicatorSizePx; + int paddingBottom = hotseatBarSizePx + pageIndicatorSizePx; if (isTablet) { // Pad the left and right of the workspace to ensure consistent spacing // between all icons @@ -515,14 +529,14 @@ public class DeviceProfile { // Folders should only appear right of the drop target bar and left of the hotseat return new Rect(mInsets.left + dropTargetBarSizePx + edgeMarginPx, mInsets.top, - mInsets.left + availableWidthPx - hotseatBarHeightPx - edgeMarginPx, + mInsets.left + availableWidthPx - hotseatBarSizePx - edgeMarginPx, mInsets.top + availableHeightPx); } else { // Folders should only appear below the drop target bar and above the hotseat return new Rect(mInsets.left, mInsets.top + dropTargetBarSizePx + edgeMarginPx, mInsets.left + availableWidthPx, - mInsets.top + availableHeightPx - hotseatBarHeightPx + mInsets.top + availableHeightPx - hotseatBarSizePx - pageIndicatorSizePx - edgeMarginPx); } } @@ -609,38 +623,44 @@ public class DeviceProfile { if (hasVerticalBarLayout) { // Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the // screen regardless of RTL - lp.gravity = Gravity.RIGHT; - lp.width = hotseatBarHeightPx + mInsets.left + mInsets.right; - lp.height = LayoutParams.MATCH_PARENT; - int paddingRight = mInsets.left > 0 ? hotseatBarLeftNavBarRightPaddingPx : hotseatBarRightNavBarRightPaddingPx; + int paddingLeft = mInsets.left > 0 + ? hotseatBarLeftNavBarLeftPaddingPx + : hotseatBarRightNavBarLeftPaddingPx; - hotseat.getLayout().setPadding(mInsets.left + cellLayoutPaddingLeftRightPx, - mInsets.top, mInsets.right + paddingRight + cellLayoutPaddingLeftRightPx, - workspacePadding.bottom); + lp.gravity = Gravity.RIGHT; + lp.width = hotseatBarSizePx + mInsets.left + mInsets.right + + paddingLeft + paddingRight; + lp.height = LayoutParams.MATCH_PARENT; + + hotseat.getLayout().setPadding(mInsets.left + cellLayoutPaddingLeftRightPx + + paddingLeft, + mInsets.top, + mInsets.right + cellLayoutPaddingLeftRightPx + paddingRight, + workspacePadding.bottom + cellLayoutBottomPaddingPx); } else if (isTablet) { // Pad the hotseat with the workspace padding calculated above lp.gravity = Gravity.BOTTOM; lp.width = LayoutParams.MATCH_PARENT; - lp.height = hotseatBarHeightPx + mInsets.bottom; + lp.height = hotseatBarSizePx + mInsets.bottom; hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx, hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx, - hotseatBarBottomPaddingPx + mInsets.bottom); + hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx); } else { // For phones, layout the hotseat without any bottom margin // to ensure that we have space for the folders lp.gravity = Gravity.BOTTOM; lp.width = LayoutParams.MATCH_PARENT; - lp.height = hotseatBarHeightPx + mInsets.bottom; + lp.height = hotseatBarSizePx + mInsets.bottom; hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx, hotseatBarTopPaddingPx, hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx, - hotseatBarBottomPaddingPx + mInsets.bottom); + hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx); } hotseat.setLayoutParams(lp); @@ -659,7 +679,7 @@ public class DeviceProfile { // Put the page indicators above the hotseat lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; lp.height = pageIndicatorSizePx; - lp.bottomMargin = hotseatBarHeightPx + mInsets.bottom; + lp.bottomMargin = hotseatBarSizePx + mInsets.bottom; } pageIndicator.setLayoutParams(lp); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 4b3148626..8492a7985 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -119,6 +119,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.util.ActivityResultInfo; +import com.android.launcher3.util.RunnableWithId; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.MultiHashMap; @@ -144,6 +145,10 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.Executor; + +import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS; +import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS; /** * Default launcher application. @@ -245,7 +250,6 @@ public class Launcher extends BaseActivity // Main container view and the model for the widget tray screen. @Thunk WidgetsContainerView mWidgetsView; - @Thunk MultiHashMap<PackageItemInfo, WidgetItem> mAllWidgets; // 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. @@ -465,9 +469,6 @@ public class Launcher extends BaseActivity setOrientation(); setContentView(mLauncherView); - if (mLauncherCallbacks != null) { - mLauncherCallbacks.onCreate(savedInstanceState); - } // Listen for broadcasts IntentFilter filter = new IntentFilter(); @@ -478,6 +479,10 @@ public class Launcher extends BaseActivity getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW, Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)); + + if (mLauncherCallbacks != null) { + mLauncherCallbacks.onCreate(savedInstanceState); + } } @Override @@ -959,6 +964,9 @@ public class Launcher extends BaseActivity } else if (mOnResumeState == State.WIDGETS) { showWidgetsView(false, false); } + if (mOnResumeState != State.APPS) { + tryAndUpdatePredictedApps(); + } mOnResumeState = State.NONE; mPaused = false; @@ -1302,9 +1310,7 @@ public class Launcher extends BaseActivity mDragController.addDropTarget(mWorkspace); mDropTargetBar.setup(mDragController); - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) { - mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace); - } + mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace); if (TestingUtils.MEMORY_DUMP_ENABLED) { TestingUtils.addWeightWatcher(this); @@ -1851,6 +1857,8 @@ public class Launcher extends BaseActivity LauncherAnimUtils.onDestroyActivity(); + clearPendingBinds(); + if (mLauncherCallbacks != null) { mLauncherCallbacks.onDestroy(); } @@ -2270,7 +2278,7 @@ public class Launcher extends BaseActivity if (v instanceof FolderIcon) { onClickFolderIcon(v); } - } else if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator) || + } else if ((v instanceof PageIndicator) || (v == mAllAppsButton && mAllAppsButton != null)) { onClickAllAppsButton(v); } else if (tag instanceof AppInfo) { @@ -3106,12 +3114,12 @@ public class Launcher extends BaseActivity * * @return {@code true} if we are currently paused. The caller might be able to skip some work */ - @Thunk boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) { + @Thunk boolean waitUntilResume(Runnable run) { if (mPaused) { if (LOGD) Log.d(TAG, "Deferring update until onResume"); - if (deletePreviousRunnables) { - while (mBindOnResumeCallbacks.remove(run)) { - } + if (run instanceof RunnableWithId) { + // Remove any runnables which have the same id + while (mBindOnResumeCallbacks.remove(run)) { } } mBindOnResumeCallbacks.add(run); return true; @@ -3120,10 +3128,6 @@ public class Launcher extends BaseActivity } } - private boolean waitUntilResume(Runnable run) { - return waitUntilResume(run, false); - } - public void addOnResumeCallback(Runnable run) { mOnResumeCallbacks.add(run); } @@ -3242,13 +3246,13 @@ public class Launcher extends BaseActivity } } + @Override public void bindAppsAdded(final ArrayList<Long> newScreens, final ArrayList<ItemInfo> addNotAnimated, - final ArrayList<ItemInfo> addAnimated, - final ArrayList<AppInfo> addedApps) { + final ArrayList<ItemInfo> addAnimated) { Runnable r = new Runnable() { public void run() { - bindAppsAdded(newScreens, addNotAnimated, addAnimated, addedApps); + bindAppsAdded(newScreens, addNotAnimated, addAnimated); } }; if (waitUntilResume(r)) { @@ -3263,20 +3267,14 @@ public class Launcher extends BaseActivity // We add the items without animation on non-visible pages, and with // animations on the new page (which we will try and snap to). if (addNotAnimated != null && !addNotAnimated.isEmpty()) { - bindItems(addNotAnimated, 0, - addNotAnimated.size(), false); + bindItems(addNotAnimated, false); } if (addAnimated != null && !addAnimated.isEmpty()) { - bindItems(addAnimated, 0, - addAnimated.size(), true); + bindItems(addAnimated, true); } // Remove the extra empty screen mWorkspace.removeExtraEmptyScreen(false, false); - - if (addedApps != null && mAppsView != null) { - mAppsView.addApps(addedApps); - } } /** @@ -3285,11 +3283,10 @@ public class Launcher extends BaseActivity * Implementation of the method from LauncherModel.Callbacks. */ @Override - public void bindItems(final ArrayList<ItemInfo> items, final int start, final int end, - final boolean forceAnimateIcons) { + public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) { Runnable r = new Runnable() { public void run() { - bindItems(items, start, end, forceAnimateIcons); + bindItems(items, forceAnimateIcons); } }; if (waitUntilResume(r)) { @@ -3302,7 +3299,8 @@ public class Launcher extends BaseActivity final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation(); Workspace workspace = mWorkspace; long newItemsScreenId = -1; - for (int i = start; i < end; i++) { + int end = items.size(); + for (int i = 0; i < end; i++) { final ItemInfo item = items.get(i); // Short circuit if we are loading dock items for a configuration which has no dock @@ -3327,19 +3325,10 @@ public class Launcher extends BaseActivity break; } case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: { - LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item; - if (mIsSafeModeEnabled) { - view = new PendingAppWidgetHostView(this, info, mIconCache, true); - } else { - LauncherAppWidgetProviderInfo providerInfo = - mAppWidgetManager.getLauncherAppWidgetInfo(info.appWidgetId); - if (providerInfo == null) { - deleteWidgetInfo(info); - continue; - } - view = mAppWidgetHost.createView(this, info.appWidgetId, providerInfo); + view = inflateAppWidget((LauncherAppWidgetInfo) item); + if (view == null) { + continue; } - prepareAppWidget((AppWidgetHostView) view, info); break; } default: @@ -3409,26 +3398,21 @@ public class Launcher extends BaseActivity /** * Add the views for a widget to the workspace. - * - * Implementation of the method from LauncherModel.Callbacks. */ - public void bindAppWidget(final LauncherAppWidgetInfo item) { - Runnable r = new Runnable() { - public void run() { - bindAppWidget(item); - } - }; - if (waitUntilResume(r)) { - return; + public void bindAppWidget(LauncherAppWidgetInfo item) { + View view = inflateAppWidget(item); + if (view != null) { + mWorkspace.addInScreen(view, item); + mWorkspace.requestLayout(); } + } + private View inflateAppWidget(LauncherAppWidgetInfo item) { if (mIsSafeModeEnabled) { PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, mIconCache, true); prepareAppWidget(view, item); - mWorkspace.addInScreen(view, item); - mWorkspace.requestLayout(); - return; + return view; } final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0; @@ -3458,7 +3442,7 @@ public class Launcher extends BaseActivity + ", as the provider is null"); } getModelWriter().deleteItemFromDatabase(item); - return; + return null; } // If we do not have a valid id, try to bind an id. @@ -3526,7 +3510,7 @@ public class Launcher extends BaseActivity if (appWidgetInfo == null) { FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId); deleteWidgetInfo(item); - return; + return null; } item.minSpanX = appWidgetInfo.minSpanX; @@ -3536,13 +3520,12 @@ public class Launcher extends BaseActivity view = new PendingAppWidgetHostView(this, item, mIconCache, false); } prepareAppWidget(view, item); - mWorkspace.addInScreen(view, item); - mWorkspace.requestLayout(); if (DEBUG_WIDGETS) { Log.d(TAG, "bound widget id="+item.appWidgetId+" in " + (SystemClock.uptimeMillis()-start) + "ms"); } + return view; } /** @@ -3678,29 +3661,28 @@ public class Launcher extends BaseActivity } /** - * A runnable that we can dequeue and re-enqueue when all applications are bound (to prevent - * multiple calls to bind the same list.) - */ - @Thunk ArrayList<AppInfo> mTmpAppsList; - private final Runnable mBindAllApplicationsRunnable = new Runnable() { - public void run() { - bindAllApplications(mTmpAppsList); - mTmpAppsList = null; - } - }; - - /** * Add the icons for all apps. * * Implementation of the method from LauncherModel.Callbacks. */ public void bindAllApplications(final ArrayList<AppInfo> apps) { - if (waitUntilResume(mBindAllApplicationsRunnable, true)) { - mTmpAppsList = apps; + Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) { + public void run() { + bindAllApplications(apps); + } + }; + if (waitUntilResume(r)) { return; } if (mAppsView != null) { + Executor pendingExecutor = getPendingExecutor(); + if (pendingExecutor != null && mState != State.APPS) { + // Wait until the fade in animation has finished before setting all apps list. + pendingExecutor.execute(r); + return; + } + mAppsView.setApps(apps); } if (mLauncherCallbacks != null) { @@ -3709,6 +3691,14 @@ public class Launcher extends BaseActivity } /** + * Returns an Executor that will run after the launcher is first drawn (including after the + * initial fade in animation). Returns null if the first draw has already occurred. + */ + public @Nullable Executor getPendingExecutor() { + return mPendingExecutor != null && mPendingExecutor.canQueue() ? mPendingExecutor : null; + } + + /** * Copies LauncherModel's map of activities to shortcut ids to Launcher's. This is necessary * because LauncherModel's map is updated in the background, while Launcher runs on the UI. */ @@ -3722,10 +3712,10 @@ public class Launcher extends BaseActivity * * Implementation of the method from LauncherModel.Callbacks. */ - public void bindAppsUpdated(final ArrayList<AppInfo> apps) { + public void bindAppsAddedOrUpdated(final ArrayList<AppInfo> apps) { Runnable r = new Runnable() { public void run() { - bindAppsUpdated(apps); + bindAppsAddedOrUpdated(apps); } }; if (waitUntilResume(r)) { @@ -3733,7 +3723,7 @@ public class Launcher extends BaseActivity } if (mAppsView != null) { - mAppsView.updateApps(apps); + mAppsView.addOrUpdateApps(apps); } } @@ -3771,16 +3761,12 @@ public class Launcher extends BaseActivity * Implementation of the method from LauncherModel.Callbacks. * * @param updated list of shortcuts which have changed. - * @param removed list of shortcuts which were deleted in the background. This can happen when - * an app gets removed from the system or some of its components are no longer - * available. */ @Override - public void bindShortcutsChanged(final ArrayList<ShortcutInfo> updated, - final ArrayList<ShortcutInfo> removed, final UserHandle user) { + public void bindShortcutsChanged(final ArrayList<ShortcutInfo> updated, final UserHandle user) { Runnable r = new Runnable() { public void run() { - bindShortcutsChanged(updated, removed, user); + bindShortcutsChanged(updated, user); } }; if (waitUntilResume(r)) { @@ -3790,31 +3776,6 @@ public class Launcher extends BaseActivity if (!updated.isEmpty()) { mWorkspace.updateShortcuts(updated); } - - if (!removed.isEmpty()) { - HashSet<ComponentName> removedComponents = new HashSet<>(); - HashSet<ShortcutKey> removedDeepShortcuts = new HashSet<>(); - - for (ShortcutInfo si : removed) { - if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - removedDeepShortcuts.add(ShortcutKey.fromItemInfo(si)); - } else { - removedComponents.add(si.getTargetComponent()); - } - } - - if (!removedComponents.isEmpty()) { - ItemInfoMatcher matcher = ItemInfoMatcher.ofComponents(removedComponents, user); - mWorkspace.removeItemsByMatcher(matcher); - mDragController.onAppsRemoved(matcher); - } - - if (!removedDeepShortcuts.isEmpty()) { - ItemInfoMatcher matcher = ItemInfoMatcher.ofShortcutKeys(removedDeepShortcuts); - mWorkspace.removeItemsByMatcher(matcher); - mDragController.onAppsRemoved(matcher); - } - } } /** @@ -3844,28 +3805,17 @@ public class Launcher extends BaseActivity * package-removal should clear all items by package name. */ @Override - public void bindWorkspaceComponentsRemoved( - final HashSet<String> packageNames, final HashSet<ComponentName> components, - final UserHandle user) { + public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) { Runnable r = new Runnable() { public void run() { - bindWorkspaceComponentsRemoved(packageNames, components, user); + bindWorkspaceComponentsRemoved(matcher); } }; if (waitUntilResume(r)) { return; } - if (!packageNames.isEmpty()) { - ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageNames, user); - mWorkspace.removeItemsByMatcher(matcher); - mDragController.onAppsRemoved(matcher); - - } - if (!components.isEmpty()) { - ItemInfoMatcher matcher = ItemInfoMatcher.ofComponents(components, user); - mWorkspace.removeItemsByMatcher(matcher); - mDragController.onAppsRemoved(matcher); - } + mWorkspace.removeItemsByMatcher(matcher); + mDragController.onAppsRemoved(matcher); } @Override @@ -3886,22 +3836,25 @@ public class Launcher extends BaseActivity } } - private final Runnable mBindAllWidgetsRunnable = new Runnable() { + @Override + public void bindAllWidgets(final MultiHashMap<PackageItemInfo, WidgetItem> allWidgets) { + Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_WIDGETS) { + @Override public void run() { - bindAllWidgets(mAllWidgets); + bindAllWidgets(allWidgets); } }; - - @Override - public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> allWidgets) { - if (waitUntilResume(mBindAllWidgetsRunnable, true)) { - mAllWidgets = allWidgets; + if (waitUntilResume(r)) { return; } if (mWidgetsView != null && allWidgets != null) { + Executor pendingExecutor = getPendingExecutor(); + if (pendingExecutor != null && mState != State.WIDGETS) { + pendingExecutor.execute(r); + return; + } mWidgetsView.setWidgets(allWidgets); - mAllWidgets = null; } AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index cf20febd5..1ffe41bc6 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; @@ -28,13 +29,17 @@ import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dynamicui.ExtractionUtils; +import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.util.ConfigMonitor; import com.android.launcher3.util.Preconditions; +import com.android.launcher3.util.SettingsObserver; import com.android.launcher3.util.TestingUtils; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING; + public class LauncherAppState { public static final boolean PROFILE_STARTUP = FeatureFlags.IS_DOGFOOD_BUILD; @@ -47,7 +52,7 @@ public class LauncherAppState { private final IconCache mIconCache; private final WidgetPreviewLoader mWidgetCache; private final InvariantDeviceProfile mInvariantDeviceProfile; - + private final SettingsObserver mNotificationBadgingObserver; public static LauncherAppState getInstance(final Context context) { if (INSTANCE == null) { @@ -117,6 +122,23 @@ public class LauncherAppState { new ConfigMonitor(mContext).register(); ExtractionUtils.startColorExtractionServiceIfNecessary(mContext); + + if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) { + mNotificationBadgingObserver = null; + } else { + // Register an observer to rebind the notification listener when badging is re-enabled. + mNotificationBadgingObserver = new SettingsObserver.Secure( + mContext.getContentResolver()) { + @Override + public void onSettingChanged(boolean isNotificationBadgingEnabled) { + if (isNotificationBadgingEnabled) { + NotificationListener.requestRebind(new ComponentName( + mContext, NotificationListener.class)); + } + } + }; + mNotificationBadgingObserver.register(NOTIFICATION_BADGING); + } } /** @@ -127,6 +149,9 @@ public class LauncherAppState { final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); launcherApps.removeOnAppsChangedCallback(mModel); PackageInstallerCompat.getInstance(mContext).onStop(); + if (mNotificationBadgingObserver != null) { + mNotificationBadgingObserver.unregister(); + } } LauncherModel setLauncher(Launcher launcher) { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index f1638fda2..a906b00f1 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -56,6 +56,7 @@ import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.ShortcutInfoCompat; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; @@ -138,26 +139,20 @@ public class LauncherModel extends BroadcastReceiver public int getCurrentWorkspaceScreen(); public void clearPendingBinds(); public void startBinding(); - public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end, - boolean forceAnimateIcons); + public void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons); public void bindScreens(ArrayList<Long> orderedScreenIds); public void finishFirstPageBind(ViewOnDrawExecutor executor); public void finishBindingItems(); - public void bindAppWidget(LauncherAppWidgetInfo info); public void bindAllApplications(ArrayList<AppInfo> apps); + public void bindAppsAddedOrUpdated(ArrayList<AppInfo> apps); public void bindAppsAdded(ArrayList<Long> newScreens, ArrayList<ItemInfo> addNotAnimated, - ArrayList<ItemInfo> addAnimated, - ArrayList<AppInfo> addedApps); - public void bindAppsUpdated(ArrayList<AppInfo> apps); + ArrayList<ItemInfo> addAnimated); public void bindPromiseAppProgressUpdated(PromiseAppInfo app); - public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, - ArrayList<ShortcutInfo> removed, UserHandle user); + public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, UserHandle user); public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets); public void bindRestoreItemsChange(HashSet<ItemInfo> updates); - public void bindWorkspaceComponentsRemoved( - HashSet<String> packageNames, HashSet<ComponentName> components, - UserHandle user); + public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher); public void bindAppInfosRemoved(ArrayList<AppInfo> appInfos); public void bindAllWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets); public void onPageBoundSynchronously(int page); @@ -537,7 +532,7 @@ public class LauncherModel extends BroadcastReceiver scheduleCallbackTask(new CallbackTask() { @Override public void execute(Callbacks callbacks) { - callbacks.bindAppsAdded(null, null, null, arrayList); + callbacks.bindAppsAddedOrUpdated(arrayList); } }); } @@ -689,4 +684,8 @@ public class LauncherModel extends BroadcastReceiver public static Looper getWorkerLooper() { return sWorkerThread.getLooper(); } + + public static void setWorkerPriority(final int priority) { + Process.setThreadPriority(sWorkerThread.getThreadId(), priority); + } } diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java index 643d48adf..a81432363 100644 --- a/src/com/android/launcher3/LauncherRootView.java +++ b/src/com/android/launcher3/LauncherRootView.java @@ -11,6 +11,9 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewDebug; +import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV; +import static com.android.launcher3.util.SystemUiController.UI_STATE_ROOT_VIEW; + public class LauncherRootView extends InsettableFrameLayout { private final Paint mOpaquePaint; @@ -44,20 +47,28 @@ public class LauncherRootView extends InsettableFrameLayout { @TargetApi(23) @Override protected boolean fitSystemWindows(Rect insets) { - boolean rawInsetsChanged = !mInsets.equals(insets); mDrawSideInsetBar = (insets.right > 0 || insets.left > 0) && (!Utilities.ATLEAST_MARSHMALLOW || - getContext().getSystemService(ActivityManager.class).isLowRamDevice()); - mRightInsetBarWidth = insets.right; - mLeftInsetBarWidth = insets.left; - setInsets(mDrawSideInsetBar ? new Rect(0, insets.top, 0, insets.bottom) : insets); + getContext().getSystemService(ActivityManager.class).isLowRamDevice()); + if (mDrawSideInsetBar) { + mLeftInsetBarWidth = insets.left; + mRightInsetBarWidth = insets.right; + insets = new Rect(0, insets.top, 0, insets.bottom); + } else { + mLeftInsetBarWidth = mRightInsetBarWidth = 0; + } + Launcher.getLauncher(getContext()).getSystemUiController().updateUiState( + UI_STATE_ROOT_VIEW, mDrawSideInsetBar ? FLAG_DARK_NAV : 0); + + boolean rawInsetsChanged = !mInsets.equals(insets); + setInsets(insets); - if (mAlignedView != null && mDrawSideInsetBar) { + if (mAlignedView != null) { // Apply margins on aligned view to handle left/right insets. MarginLayoutParams lp = (MarginLayoutParams) mAlignedView.getLayoutParams(); - if (lp.leftMargin != insets.left || lp.rightMargin != insets.right) { - lp.leftMargin = insets.left; - lp.rightMargin = insets.right; + if (lp.leftMargin != mLeftInsetBarWidth || lp.rightMargin != mRightInsetBarWidth) { + lp.leftMargin = mLeftInsetBarWidth; + lp.rightMargin = mRightInsetBarWidth; mAlignedView.setLayoutParams(lp); } } diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index 44b9704f2..e2474900d 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -80,13 +80,11 @@ import com.android.launcher3.widget.WidgetsContainerView; public class LauncherStateTransitionAnimation { /** - * animation used for all apps and widget tray when - *{@link FeatureFlags#LAUNCHER3_ALL_APPS_PULL_UP} is {@code false} + * animation used for the widget tray */ public static final int CIRCULAR_REVEAL = 0; /** - * animation used for all apps and not widget tray when - *{@link FeatureFlags#LAUNCHER3_ALL_APPS_PULL_UP} is {@code true} + * animation used for all apps tray */ public static final int PULLUP = 1; @@ -154,13 +152,9 @@ public class LauncherStateTransitionAnimation { mLauncher.getUserEventDispatcher().resetElapsedContainerMillis(); } }; - int animType = CIRCULAR_REVEAL; - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) { - animType = PULLUP; - } // Only animate the search bar if animating from spring loaded mode back to all apps startAnimationToOverlay( - Workspace.State.NORMAL_HIDDEN, buttonView, toView, animated, animType, cb); + Workspace.State.NORMAL_HIDDEN, buttonView, toView, animated, PULLUP, cb); } /** @@ -193,12 +187,8 @@ public class LauncherStateTransitionAnimation { if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED || mAllAppsController.isTransitioning()) { - int animType = CIRCULAR_REVEAL; - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) { - animType = PULLUP; - } startAnimationToWorkspaceFromAllApps(fromWorkspaceState, toWorkspaceState, - animated, animType, onCompleteRunnable); + animated, PULLUP, onCompleteRunnable); } else if (fromState == Launcher.State.WIDGETS || fromState == Launcher.State.WIDGETS_SPRING_LOADED) { startAnimationToWorkspaceFromWidgets(fromWorkspaceState, toWorkspaceState, @@ -235,8 +225,7 @@ public class LauncherStateTransitionAnimation { playCommonTransitionAnimations(toWorkspaceState, animated, initialized, animation, layerViews); if (!animated || !initialized) { - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && - toWorkspaceState == Workspace.State.NORMAL_HIDDEN) { + if (toWorkspaceState == Workspace.State.NORMAL_HIDDEN) { mAllAppsController.finishPullUp(); } toView.setTranslationX(0.0f); @@ -338,8 +327,10 @@ public class LauncherStateTransitionAnimation { toView.post(new StartAnimRunnable(animation, toView)); mCurrentAnimation = animation; } else if (animType == PULLUP) { - // We are animating the content view alpha, so ensure we have a layer for it - layerViews.addView(contentView); + if (!FeatureFlags.LAUNCHER3_PHYSICS) { + // We are animating the content view alpha, so ensure we have a layer for it. + layerViews.addView(contentView); + } animation.addListener(new AnimatorListenerAdapter() { @Override @@ -525,8 +516,7 @@ public class LauncherStateTransitionAnimation { playCommonTransitionAnimations(toWorkspaceState, animated, initialized, animation, layerViews); if (!animated || !initialized) { - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && - fromWorkspaceState == Workspace.State.NORMAL_HIDDEN) { + if (fromWorkspaceState == Workspace.State.NORMAL_HIDDEN) { mAllAppsController.finishPullDown(); } fromView.setVisibility(View.GONE); diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java index d5d5eab76..90463725f 100644 --- a/src/com/android/launcher3/SettingsActivity.java +++ b/src/com/android/launcher3/SettingsActivity.java @@ -26,18 +26,15 @@ import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.database.ContentObserver; import android.os.Bundle; -import android.os.Handler; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceFragment; import android.provider.Settings; -import android.provider.Settings.System; -import android.view.View; import com.android.launcher3.graphics.IconShapeOverride; import com.android.launcher3.notification.NotificationListener; +import com.android.launcher3.util.SettingsObserver; import com.android.launcher3.views.ButtonPreference; /** @@ -46,8 +43,8 @@ import com.android.launcher3.views.ButtonPreference; public class SettingsActivity extends Activity { private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging"; - // TODO: use Settings.Secure.NOTIFICATION_BADGING - private static final String NOTIFICATION_BADGING = "notification_badging"; + /** Hidden field Settings.Secure.NOTIFICATION_BADGING */ + public static final String NOTIFICATION_BADGING = "notification_badging"; /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */ private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners"; @@ -89,12 +86,9 @@ public class SettingsActivity extends Activity { // Register a content observer to listen for system setting changes while // this UI is active. - resolver.registerContentObserver( - Settings.System.getUriFor(System.ACCELEROMETER_ROTATION), - false, mRotationLockObserver); + mRotationLockObserver.register(Settings.System.ACCELEROMETER_ROTATION); // Initialize the UI once - mRotationLockObserver.onChange(true); rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity())); } @@ -108,13 +102,7 @@ public class SettingsActivity extends Activity { // Listen to system notification badge settings while this UI is active. mIconBadgingObserver = new IconBadgingObserver( iconBadgingPref, resolver, getFragmentManager()); - resolver.registerContentObserver( - Settings.Secure.getUriFor(NOTIFICATION_BADGING), - false, mIconBadgingObserver); - resolver.registerContentObserver( - Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS), - false, mIconBadgingObserver); - mIconBadgingObserver.onChange(true); + mIconBadgingObserver.register(NOTIFICATION_BADGING, NOTIFICATION_ENABLED_LISTENERS); } Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE); @@ -130,11 +118,11 @@ public class SettingsActivity extends Activity { @Override public void onDestroy() { if (mRotationLockObserver != null) { - getActivity().getContentResolver().unregisterContentObserver(mRotationLockObserver); + mRotationLockObserver.unregister(); mRotationLockObserver = null; } if (mIconBadgingObserver != null) { - getActivity().getContentResolver().unregisterContentObserver(mIconBadgingObserver); + mIconBadgingObserver.unregister(); mIconBadgingObserver = null; } super.onDestroy(); @@ -145,22 +133,18 @@ public class SettingsActivity extends Activity { * Content observer which listens for system auto-rotate setting changes, and enables/disables * the launcher rotation setting accordingly. */ - private static class SystemDisplayRotationLockObserver extends ContentObserver { + private static class SystemDisplayRotationLockObserver extends SettingsObserver.System { private final Preference mRotationPref; - private final ContentResolver mResolver; public SystemDisplayRotationLockObserver( Preference rotationPref, ContentResolver resolver) { - super(new Handler()); + super(resolver); mRotationPref = rotationPref; - mResolver = resolver; } @Override - public void onChange(boolean selfChange) { - boolean enabled = Settings.System.getInt(mResolver, - Settings.System.ACCELEROMETER_ROTATION, 1) == 1; + public void onSettingChanged(boolean enabled) { mRotationPref.setEnabled(enabled); mRotationPref.setSummary(enabled ? R.string.allow_rotation_desc : R.string.allow_rotation_blocked_desc); @@ -171,8 +155,8 @@ public class SettingsActivity extends Activity { * Content observer which listens for system badging setting changes, * and updates the launcher badging setting subtext accordingly. */ - private static class IconBadgingObserver extends ContentObserver - implements View.OnClickListener { + private static class IconBadgingObserver extends SettingsObserver.Secure + implements Preference.OnPreferenceClickListener { private final ButtonPreference mBadgingPref; private final ContentResolver mResolver; @@ -180,15 +164,14 @@ public class SettingsActivity extends Activity { public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver, FragmentManager fragmentManager) { - super(new Handler()); + super(resolver); mBadgingPref = badgingPref; mResolver = resolver; mFragmentManager = fragmentManager; } @Override - public void onChange(boolean selfChange) { - boolean enabled = Settings.Secure.getInt(mResolver, NOTIFICATION_BADGING, 1) == 1; + public void onSettingChanged(boolean enabled) { int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off; boolean serviceEnabled = true; @@ -205,14 +188,16 @@ public class SettingsActivity extends Activity { summary = R.string.title_missing_notification_access; } } - mBadgingPref.setButtonOnClickListener(serviceEnabled ? null : this); + mBadgingPref.setWidgetFrameVisible(!serviceEnabled); + mBadgingPref.setOnPreferenceClickListener(serviceEnabled ? null : this); mBadgingPref.setSummary(summary); } @Override - public void onClick(View view) { + public boolean onPreferenceClick(Preference preference) { new NotificationAccessConfirmation().show(mFragmentManager, "notification_access"); + return true; } } diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index fd708c0fd..a7e68ff14 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -101,7 +101,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup { mInvertIfRtl = invert; } - int getCellContentHeight() { + public int getCellContentHeight() { return Math.min(getMeasuredHeight(), mLauncher.getDeviceProfile().getCellHeight(mContainerType)); } diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java index 45c14d6bb..e15cf9f50 100644 --- a/src/com/android/launcher3/UninstallDropTarget.java +++ b/src/com/android/launcher3/UninstallDropTarget.java @@ -42,7 +42,7 @@ public class UninstallDropTarget extends ButtonDropTarget { return supportsDrop(getContext(), info); } - public static boolean supportsDrop(Context context, Object info) { + public static boolean supportsDrop(Context context, ItemInfo info) { UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = userManager.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) @@ -56,21 +56,13 @@ public class UninstallDropTarget extends ButtonDropTarget { /** * @return the component name that should be uninstalled or null. */ - private static ComponentName getUninstallTarget(Context context, Object item) { + private static ComponentName getUninstallTarget(Context context, ItemInfo item) { Intent intent = null; UserHandle user = null; - if (item instanceof AppInfo) { - AppInfo info = (AppInfo) item; - intent = info.intent; - user = info.user; - } else if (item instanceof ShortcutInfo) { - ShortcutInfo info = (ShortcutInfo) item; - if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) { - // Do not use restore/target intent here as we cannot uninstall an app which is - // being installed/restored. - intent = info.intent; - user = info.user; - } + if (item != null && + item.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) { + intent = item.getIntent(); + user = item.user; } if (intent != null) { LauncherActivityInfo info = LauncherAppsCompat.getInstance(context) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index a2270d6c5..f8d64984e 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -671,7 +671,8 @@ public class Workspace extends PagedView newScreen.setSoundEffectsEnabled(false); int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx; - newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, 0); + int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx; + newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom); mWorkspaceScreens.put(screenId, newScreen); mScreenOrder.add(insertIndex, screenId); diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 32deaf286..a105a7303 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -273,10 +273,8 @@ public class WorkspaceStateTransitionAnimation { float finalBackgroundAlpha = (states.stateIsSpringLoaded || states.stateIsOverview) ? 1.0f : 0f; float finalHotseatAlpha = (states.stateIsNormal || states.stateIsSpringLoaded || - (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f; - float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f; - float finalQsbAlpha = (states.stateIsNormal || - (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f; + states.stateIsNormalHidden) ? 1f : 0f; + float finalQsbAlpha = (states.stateIsNormal || states.stateIsNormalHidden) ? 1f : 0f; float finalWorkspaceTranslationY = 0; if (states.stateIsOverview || states.stateIsOverviewHidden) { @@ -313,8 +311,7 @@ public class WorkspaceStateTransitionAnimation { if (states.stateIsOverviewHidden) { finalAlpha = 0f; } else if(states.stateIsNormalHidden) { - finalAlpha = (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && - i == mWorkspace.getNextPage()) ? 1 : 0; + finalAlpha = (i == mWorkspace.getNextPage()) ? 1 : 0; } else if (states.stateIsNormal && mWorkspaceFadeInAdjacentScreens) { finalAlpha = (i == toPage || i < customPageCount) ? 1f : 0f; } else { @@ -323,7 +320,7 @@ public class WorkspaceStateTransitionAnimation { // If we are animating to/from the small state, then hide the side pages and fade the // current page in - if (!FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && !mWorkspace.isSwitchingState()) { + if (!FeatureFlags.NO_ALL_APPS_ICON && !mWorkspace.isSwitchingState()) { if (states.workspaceToAllApps || states.allAppsToWorkspace) { boolean isCurrentPage = (i == toPage); if (states.allAppsToWorkspace && isCurrentPage) { @@ -359,38 +356,47 @@ public class WorkspaceStateTransitionAnimation { final ViewGroup overviewPanel = mLauncher.getOverviewPanel(); + float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f; if (animated) { + // This is true when transitioning between: + // - Overview <-> Workspace + // - Overview <-> Widget Tray + if (finalOverviewPanelAlpha != overviewPanel.getAlpha()) { + Animator overviewPanelAlpha = ObjectAnimator.ofFloat( + overviewPanel, View.ALPHA, finalOverviewPanelAlpha); + overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel, + accessibilityEnabled)); + layerViews.addView(overviewPanel); + + if (states.overviewToWorkspace) { + overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2)); + } else if (states.workspaceToOverview) { + overviewPanelAlpha.setInterpolator(null); + } + + overviewPanelAlpha.setDuration(duration); + mStateAnimator.play(overviewPanelAlpha); + } + Animator scale = LauncherAnimUtils.ofPropertyValuesHolder(mWorkspace, new PropertyListBuilder().scale(mNewScale) .translationY(finalWorkspaceTranslationY).build()) .setDuration(duration); scale.setInterpolator(mZoomInInterpolator); mStateAnimator.play(scale); - Animator hotseatAlpha = mWorkspace.createHotseatAlphaAnimator(finalHotseatAlpha); - - Animator overviewPanelAlpha = ObjectAnimator.ofFloat( - overviewPanel, View.ALPHA, finalOverviewPanelAlpha); - overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel, - accessibilityEnabled)); // For animation optimization, we may need to provide the Launcher transition // with a set of views on which to force build and manage layers in certain scenarios. - layerViews.addView(overviewPanel); layerViews.addView(mLauncher.getHotseat()); layerViews.addView(mWorkspace.getPageIndicator()); + Animator hotseatAlpha = mWorkspace.createHotseatAlphaAnimator(finalHotseatAlpha); if (states.workspaceToOverview) { hotseatAlpha.setInterpolator(new DecelerateInterpolator(2)); - overviewPanelAlpha.setInterpolator(null); } else if (states.overviewToWorkspace) { hotseatAlpha.setInterpolator(null); - overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2)); } - - overviewPanelAlpha.setDuration(duration); hotseatAlpha.setDuration(duration); - - mStateAnimator.play(overviewPanelAlpha); mStateAnimator.play(hotseatAlpha); mStateAnimator.addListener(new AnimatorListenerAdapter() { boolean canceled = false; diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index 34335330b..a0ad07aeb 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -173,7 +173,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme ArrayList<ItemInfo> itemList = new ArrayList<>(); itemList.add(info); - mLauncher.bindItems(itemList, 0, itemList.size(), true); + mLauncher.bindItems(itemList, true); } else if (item instanceof PendingAddItemInfo) { PendingAddItemInfo info = (PendingAddItemInfo) item; Workspace workspace = mLauncher.getWorkspace(); @@ -205,7 +205,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme public void run() { ArrayList<ItemInfo> itemList = new ArrayList<>(); itemList.add(item); - mLauncher.bindItems(itemList, 0, itemList.size(), true); + mLauncher.bindItems(itemList, true); announceConfirmation(R.string.item_moved); } }); diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java index b7c500fa6..5b7353aa1 100644 --- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java @@ -73,7 +73,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele screenId, coordinates[0], coordinates[1]); ArrayList<ItemInfo> itemList = new ArrayList<>(); itemList.add(info); - mLauncher.bindItems(itemList, 0, itemList.size(), true); + mLauncher.bindItems(itemList, true); AbstractFloatingView.closeAllOpenViews(mLauncher); announceConfirmation(R.string.item_added_to_workspace); } diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 0083d47f2..97a87c16c 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -102,18 +102,14 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc @Override protected void updateBackground( int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) { - if (mLauncher.getDeviceProfile().isVerticalBarLayout()) { - getRevealView().setBackground(new InsetDrawable(mBaseDrawable, - paddingLeft, paddingTop, paddingRight, paddingBottom)); - getContentView().setBackground( - new InsetDrawable(new ColorDrawable(Color.TRANSPARENT), - paddingLeft, paddingTop, paddingRight, paddingBottom)); - } else { - getRevealView().setBackground(mBaseDrawable); - } + if (mLauncher.getDeviceProfile().isVerticalBarLayout()) { + getRevealView().setBackground(new InsetDrawable(mBaseDrawable, + paddingLeft, paddingTop, paddingRight, paddingBottom)); + getContentView().setBackground( + new InsetDrawable(new ColorDrawable(Color.TRANSPARENT), + paddingLeft, paddingTop, paddingRight, paddingBottom)); } else { - super.updateBackground(paddingLeft, paddingTop, paddingRight, paddingBottom); + getRevealView().setBackground(mBaseDrawable); } } @@ -132,18 +128,10 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc } /** - * Adds new apps to the list. - */ - public void addApps(List<AppInfo> apps) { - mApps.addApps(apps); - mSearchUiManager.refreshSearchResult(); - } - - /** - * Updates existing apps in the list + * Adds or updates existing apps in the list */ - public void updateApps(List<AppInfo> apps) { - mApps.updateApps(apps); + public void addOrUpdateApps(List<AppInfo> apps) { + mApps.addOrUpdateApps(apps); mSearchUiManager.refreshSearchResult(); } @@ -224,6 +212,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc mAppsRecyclerView.setLayoutManager(mLayoutManager); mAppsRecyclerView.setAdapter(mAdapter); mAppsRecyclerView.setHasFixedSize(true); + // No animations will occur when changes occur to the items in this RecyclerView. + mAppsRecyclerView.setItemAnimator(null); if (FeatureFlags.LAUNCHER3_PHYSICS) { mAppsRecyclerView.setSpringAnimationHandler(mSpringAnimationHandler); } @@ -238,11 +228,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc mAppsRecyclerView.preMeasureViews(mAdapter); mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener()); - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) { - getRevealView().setVisibility(View.VISIBLE); - getContentView().setVisibility(View.VISIBLE); - getContentView().setBackground(null); - } + getRevealView().setVisibility(View.VISIBLE); + getContentView().setVisibility(View.VISIBLE); + getContentView().setBackground(null); } public SearchUiManager getSearchUiManager() { @@ -260,32 +248,15 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc // Update the number of items in the grid before we measure the view grid.updateAppsViewNumCols(); - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) { - if (mNumAppsPerRow != grid.inv.numColumns || - mNumPredictedAppsPerRow != grid.inv.numColumns) { - mNumAppsPerRow = grid.inv.numColumns; - mNumPredictedAppsPerRow = grid.inv.numColumns; - - mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow); - mAdapter.setNumAppsPerRow(mNumAppsPerRow); - mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow); - } - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - return; - } - - // --- remove START when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. --- - if (mNumAppsPerRow != grid.allAppsNumCols || - mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) { - mNumAppsPerRow = grid.allAppsNumCols; - mNumPredictedAppsPerRow = grid.allAppsNumPredictiveCols; + if (mNumAppsPerRow != grid.inv.numColumns || + mNumPredictedAppsPerRow != grid.inv.numColumns) { + mNumAppsPerRow = grid.inv.numColumns; + mNumPredictedAppsPerRow = grid.inv.numColumns; mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow); mAdapter.setNumAppsPerRow(mNumAppsPerRow); mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow); } - - // --- remove END when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. --- super.onMeasure(widthMeasureSpec, heightMeasureSpec); } diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index 331900cf1..494cd5ac5 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -111,12 +111,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine } @Override - public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) { - mPullDetector.onTouchEvent(ev); - return super.onInterceptTouchEvent(rv, ev) || mOverScrollHelper.isInOverScroll(); - } - - @Override public boolean onTouchEvent(MotionEvent e) { mPullDetector.onTouchEvent(e); if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) { @@ -205,8 +199,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine @Override public void onDraw(Canvas c) { - c.translate(0, mContentTranslationY); - // Draw the background if (mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) { mEmptySearchBackground.draw(c); @@ -215,6 +207,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine super.onDraw(c); } + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.translate(0, mContentTranslationY); + super.dispatchDraw(canvas); + canvas.translate(0, -mContentTranslationY); + } + public float getContentTranslationY() { return mContentTranslationY; } @@ -282,7 +281,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine @Override public boolean onInterceptTouchEvent(MotionEvent e) { - boolean result = super.onInterceptTouchEvent(e); + mPullDetector.onTouchEvent(e); + boolean result = super.onInterceptTouchEvent(e) || mOverScrollHelper.isInOverScroll(); if (!result && e.getAction() == MotionEvent.ACTION_DOWN && mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) { mEmptySearchBackground.setHotspot(e.getX(), e.getY()); @@ -339,6 +339,22 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine mFastScrollHelper.onSetAdapter((AllAppsGridAdapter) adapter); } + @Override + protected float getBottomFadingEdgeStrength() { + // No bottom fading edge. + return 0; + } + + @Override + protected boolean isPaddingOffsetRequired() { + return true; + } + + @Override + protected int getTopPaddingOffset() { + return -getPaddingTop(); + } + /** * Updates the bounds for the scrollbar. */ @@ -541,11 +557,16 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine // and if one of the following criteria are met: // - User scrolls down when they're already at the bottom. // - User starts scrolling up, hits the top, and continues scrolling up. + boolean wasInOverScroll = mIsInOverScroll; mIsInOverScroll = !mScrollbar.isDraggingThumb() && ((!canScrollVertically(1) && displacement < 0) || (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0)); - if (mIsInOverScroll) { + if (wasInOverScroll && !mIsInOverScroll) { + // Exit overscroll. This can happen when the user is in overscroll and then + // scrolls the opposite way. + reset(false /* shouldSpring */); + } else if (mIsInOverScroll) { if (Float.compare(mFirstDisplacement, 0) == 0) { // Because users can scroll before entering overscroll, we need to // subtract the amount where the user was not in overscroll. @@ -560,11 +581,15 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine @Override public void onDragEnd(float velocity, boolean fling) { + reset(mIsInOverScroll /* shouldSpring */); + } + + private void reset(boolean shouldSpring) { float y = getContentTranslationY(); if (Float.compare(y, 0) != 0) { - if (FeatureFlags.LAUNCHER3_PHYSICS) { + if (FeatureFlags.LAUNCHER3_PHYSICS && shouldSpring) { // We calculate our own velocity to give the springs the desired effect. - velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY; + float velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY; // We want to negate the velocity because we are moving to 0 from -1 due to the // downward motion. (y-axis -1 is above 0). mSpringAnimationHandler.animateToPositionWithVelocity(0, -1, -velocity); diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 6896b37d9..edfe0c15e 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -283,7 +283,9 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect } // Use a light system UI (dark icons) if all apps is behind at least half of the status bar. - boolean forceChange = shift <= mStatusBarHeight / 2; + boolean forceChange = FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS ? + shift <= mShiftRange / 4 : + shift <= mStatusBarHeight / 2; if (forceChange) { mLauncher.getSystemUiController().updateUiState( SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme); diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 608e898ae..5e7a5cac5 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -298,35 +298,89 @@ public class AlphabeticalAppsList { updateAdapterItems(); } + private List<AppInfo> processPredictedAppComponents(List<ComponentKey> components) { + if (mComponentToAppMap.isEmpty()) { + // Apps have not been bound yet. + return Collections.emptyList(); + } + + List<AppInfo> predictedApps = new ArrayList<>(); + for (ComponentKey ck : components) { + AppInfo info = mComponentToAppMap.get(ck); + if (info != null) { + predictedApps.add(info); + } else { + if (FeatureFlags.IS_DOGFOOD_BUILD) { + Log.e(TAG, "Predicted app not found: " + ck); + } + } + // Stop at the number of predicted apps + if (predictedApps.size() == mNumPredictedAppsPerRow) { + break; + } + } + return predictedApps; + } + /** - * Sets the current set of predicted apps. Since this can be called before we get the full set - * of applications, we should merge the results only in onAppsUpdated() which is idempotent. + * Sets the current set of predicted apps. + * + * This can be called before we get the full set of applications, we should merge the results + * only in onAppsUpdated() which is idempotent. + * + * If the number of predicted apps is the same as the previous list of predicted apps, + * we can optimize by swapping them in place. */ public void setPredictedApps(List<ComponentKey> apps) { mPredictedAppComponents.clear(); mPredictedAppComponents.addAll(apps); - onAppsUpdated(); + + List<AppInfo> newPredictedApps = processPredictedAppComponents(apps); + // We only need to do work if any of the visible predicted apps have changed. + if (!newPredictedApps.equals(mPredictedApps)) { + if (newPredictedApps.size() == mPredictedApps.size()) { + swapInNewPredictedApps(newPredictedApps); + } else { + // We need to update the appIndex of all the items. + onAppsUpdated(); + } + } } /** - * Sets the current set of apps. + * Swaps out the old predicted apps with the new predicted apps, in place. This optimization + * allows us to skip an entire relayout that would otherwise be called by notifyDataSetChanged. + * + * Note: This should only be called if the # of predicted apps is the same. + * This method assumes that predicted apps are the first items in the adapter. */ - public void setApps(List<AppInfo> apps) { - mComponentToAppMap.clear(); - addApps(apps); + private void swapInNewPredictedApps(List<AppInfo> apps) { + mPredictedApps.clear(); + mPredictedApps.addAll(apps); + + int size = apps.size(); + for (int i = 0; i < size; ++i) { + AppInfo info = apps.get(i); + AdapterItem appItem = AdapterItem.asPredictedApp(i, "", info, i); + appItem.rowAppIndex = i; + mAdapterItems.set(i, appItem); + mFilteredApps.set(i, info); + mAdapter.notifyItemChanged(i); + } } /** - * Adds new apps to the list. + * Sets the current set of apps. */ - public void addApps(List<AppInfo> apps) { - updateApps(apps); + public void setApps(List<AppInfo> apps) { + mComponentToAppMap.clear(); + addOrUpdateApps(apps); } /** - * Updates existing apps in the list + * Adds or updates existing apps in the list */ - public void updateApps(List<AppInfo> apps) { + public void addOrUpdateApps(List<AppInfo> apps) { for (AppInfo app : apps) { mComponentToAppMap.put(app.toComponentKey(), app); } @@ -432,20 +486,7 @@ public class AlphabeticalAppsList { // Process the predicted app components mPredictedApps.clear(); if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) { - for (ComponentKey ck : mPredictedAppComponents) { - AppInfo info = mComponentToAppMap.get(ck); - if (info != null) { - mPredictedApps.add(info); - } else { - if (FeatureFlags.IS_DOGFOOD_BUILD) { - Log.e(TAG, "Predicted app not found: " + ck); - } - } - // Stop at the number of predicted apps - if (mPredictedApps.size() == mNumPredictedAppsPerRow) { - break; - } - } + mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents)); if (!mPredictedApps.isEmpty()) { // Add a section for the predictions diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index 39e208874..d50455171 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -108,8 +108,7 @@ public class AppsSearchContainerLayout extends FrameLayout @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && - !mLauncher.getDeviceProfile().isVerticalBarLayout()) { + if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) { getLayoutParams().height = mLauncher.getDragLayer().getInsets().top + mMinHeight; } super.onMeasure(widthMeasureSpec, heightMeasureSpec); diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java index cdbaf708d..e9dead399 100644 --- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java +++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java @@ -71,10 +71,6 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm { return result; } - public static boolean matches(AppInfo info, String query) { - return matches(info, query, StringMatcher.getInstance()); - } - public static boolean matches(AppInfo info, String query, StringMatcher matcher) { int queryLength = query.length(); diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java b/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java index 6233fabb2..fe5ff2a8c 100644 --- a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java +++ b/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java @@ -20,6 +20,7 @@ import android.app.WallpaperManager; import android.content.Context; import android.graphics.Color; import android.os.Build; +import android.os.Handler; import android.support.annotation.Nullable; import android.util.Log; @@ -48,8 +49,7 @@ public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat { mOCLClass = Class.forName("android.app.WallpaperManager$OnColorsChangedListener"); mAddOCLMethod = WallpaperManager.class.getDeclaredMethod( - "addOnColorsChangedListener", mOCLClass); - + "addOnColorsChangedListener", mOCLClass, Handler.class); mWCGetMethod = WallpaperManager.class.getDeclaredMethod("getWallpaperColors", int.class); Class wallpaperColorsClass = mWCGetMethod.getReturnType(); mWCGetPrimaryColorMethod = wallpaperColorsClass.getDeclaredMethod("getPrimaryColor"); @@ -89,7 +89,7 @@ public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat { } }); try { - mAddOCLMethod.invoke(mWm, onChangeListener); + mAddOCLMethod.invoke(mWm, onChangeListener, null); } catch (Exception e) { Log.e(TAG, "Error calling wallpaper API", e); } diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 9e0a3b3b5..456562e2b 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -34,12 +34,11 @@ abstract class BaseFlags { public static boolean LAUNCHER3_DISABLE_ICON_NORMALIZATION = false; public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false; public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false; - public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true; public static boolean LAUNCHER3_NEW_FOLDER_ANIMATION = true; // When enabled allows to use any point on the fast scrollbar to start dragging. public static final boolean LAUNCHER3_DIRECT_SCROLL = true; // When enabled while all-apps open, the soft input will be set to adjust resize . - public static final boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = true; + public static final boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = false; // When enabled the promise icon is visible in all apps while installation an app. public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false; // When enabled uses the AllAppsRadialGradientAndScrimDrawable for all apps diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index be5f01adb..ee6a0e0b8 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -243,7 +243,7 @@ public class DragLayer extends InsettableFrameLayout { return true; } - if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && mAllAppsController.onControllerInterceptTouchEvent(ev)) { + if (mAllAppsController.onControllerInterceptTouchEvent(ev)) { mActiveController = mAllAppsController; return true; } diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index b6e38bb15..e81e2a386 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -218,6 +218,12 @@ public class DragView extends View { Rect bounds = new Rect(0, 0, w, h); bounds.inset(blurMargin, blurMargin); + // Badge is applied after icon normalization so the bounds for badge should not + // be scaled down due to icon normalization. + Rect badgeBounds = new Rect(bounds); + mBadge = getBadge(info, appState, outObj[0]); + mBadge.setBounds(badgeBounds); + Utilities.scaleRectAboutCenter(bounds, IconNormalizer.getInstance(mLauncher).getScale(dr, null, null, null)); AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) dr; @@ -234,9 +240,6 @@ public class DragView extends View { mTranslateY = new SpringFloatValue(DragView.this, h * AdaptiveIconDrawable.getExtraInsetFraction()); - mBadge = getBadge(info, appState, outObj[0]); - mBadge.setBounds(bounds); - bounds.inset( (int) (-bounds.width() * AdaptiveIconDrawable.getExtraInsetFraction()), (int) (-bounds.height() * AdaptiveIconDrawable.getExtraInsetFraction()) diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java index 678396df1..5455b43ec 100644 --- a/src/com/android/launcher3/graphics/GradientView.java +++ b/src/com/android/launcher3/graphics/GradientView.java @@ -27,6 +27,7 @@ import android.graphics.RectF; import android.graphics.Shader; import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.view.View; import android.view.animation.AccelerateInterpolator; import android.view.animation.Interpolator; @@ -46,7 +47,6 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis private static final int DEFAULT_COLOR = Color.WHITE; private static final int ALPHA_MASK_HEIGHT_DP = 500; private static final int ALPHA_MASK_WIDTH_DP = 2; - private static final int ALPHA_COLORS = 0xBF; private static final boolean DEBUG = false; private final Bitmap mAlphaGradientMask; @@ -62,7 +62,7 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis private final Paint mPaintNoScrim = new Paint(); private float mProgress; private final int mMaskHeight, mMaskWidth; - private final Context mAppContext; + private final int mAlphaColors; private final Paint mDebugPaint = DEBUG ? new Paint() : null; private final Interpolator mAccelerator = new AccelerateInterpolator(); private final float mAlphaStart; @@ -71,15 +71,14 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis public GradientView(Context context, AttributeSet attrs) { super(context, attrs); - this.mAppContext = context.getApplicationContext(); - this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, - mAppContext.getResources().getDisplayMetrics()); - this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, - mAppContext.getResources().getDisplayMetrics()); + DisplayMetrics dm = getResources().getDisplayMetrics(); + this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm); + this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm); Launcher launcher = Launcher.getLauncher(context); this.mAlphaStart = launcher.getDeviceProfile().isVerticalBarLayout() ? 0 : 100; this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor); this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher); + mAlphaColors = getResources().getInteger(R.integer.extracted_color_gradient_alpha); updateColors(); mAlphaGradientMask = createDitheredAlphaMask(); } @@ -104,9 +103,9 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis private void updateColors() { this.mColor1 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getMainColor(), - ALPHA_COLORS); + mAlphaColors); this.mColor2 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getSecondaryColor(), - ALPHA_COLORS); + mAlphaColors); if (mWidth + mHeight > 0) { createRadialShader(); } diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java index 34d0b727c..8ed62bcdc 100644 --- a/src/com/android/launcher3/graphics/IconNormalizer.java +++ b/src/com/android/launcher3/graphics/IconNormalizer.java @@ -32,10 +32,8 @@ import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; - import com.android.launcher3.LauncherAppState; import com.android.launcher3.Utilities; - import java.io.File; import java.io.FileOutputStream; import java.nio.ByteBuffer; @@ -84,12 +82,12 @@ public class IconNormalizer { private final Rect mBounds; private final Matrix mMatrix; - private Paint mPaintIcon; - private Canvas mCanvasARGB; + private final Paint mPaintIcon; + private final Canvas mCanvasARGB; - private File mDir; + private final File mDir; private int mFileId; - private Random mRandom; + private final Random mRandom; private IconNormalizer(Context context) { // Use twice the icon size as maximum size to avoid scaling down twice. @@ -122,7 +120,6 @@ public class IconNormalizer { mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); mMatrix = new Matrix(); - int[] mPixels = new int[mMaxSize * mMaxSize]; mAdaptiveIconScale = SCALE_NOT_INITIALIZED; mDir = context.getExternalFilesDir(null); @@ -174,7 +171,8 @@ public class IconNormalizer { boolean isTrans = isTransparentBitmap(mBitmapARGB); if (DEBUG) { - final File afterFile = new File(mDir, "isShape" + mFileId + "_after_" + isTrans + ".png"); + final File afterFile = new File(mDir, + "isShape" + mFileId + "_after_" + isTrans + ".png"); try { mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(afterFile)); @@ -210,7 +208,9 @@ public class IconNormalizer { float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height()); boolean transparentImage = percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD; if (DEBUG) { - Log.d(TAG, "Total # pixel that is different (id="+ mFileId + "):" + percentageDiffPixels + "="+ sum + "/" + mBounds.width() * mBounds.height()); + Log.d(TAG, + "Total # pixel that is different (id=" + mFileId + "):" + percentageDiffPixels + + "=" + sum + "/" + mBounds.width() * mBounds.height()); } return transparentImage; } diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java index 4c83e9ac2..f7f8ef18f 100644 --- a/src/com/android/launcher3/logging/FileLog.java +++ b/src/com/android/launcher3/logging/FileLog.java @@ -29,6 +29,8 @@ import java.util.concurrent.TimeUnit; */ public final class FileLog { + protected static final boolean ENABLED = + FeatureFlags.IS_DOGFOOD_BUILD || Utilities.IS_DEBUG_DEVICE; private static final String FILE_NAME_PREFIX = "log-"; private static final DateFormat DATE_FORMAT = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); @@ -39,7 +41,7 @@ public final class FileLog { private static File sLogsDirectory = null; public static void setDir(File logsDir) { - if (FeatureFlags.IS_DOGFOOD_BUILD || Utilities.IS_DEBUG_DEVICE) { + if (ENABLED) { synchronized (DATE_FORMAT) { // If the target directory changes, stop any active thread. if (sHandler != null && !logsDir.equals(sLogsDirectory)) { @@ -76,7 +78,7 @@ public final class FileLog { } public static void print(String tag, String msg, Exception e) { - if (!FeatureFlags.IS_DOGFOOD_BUILD) { + if (!ENABLED) { return; } String out = String.format("%s %s %s", DATE_FORMAT.format(new Date()), tag, msg); @@ -102,7 +104,7 @@ public final class FileLog { * @param out if not null, all the persisted logs are copied to the writer. */ public static void flushAll(PrintWriter out) throws InterruptedException { - if (!FeatureFlags.IS_DOGFOOD_BUILD) { + if (!ENABLED) { return; } CountDownLatch latch = new CountDownLatch(1); @@ -135,7 +137,7 @@ public final class FileLog { @Override public boolean handleMessage(Message msg) { - if (sLogsDirectory == null || !FeatureFlags.IS_DOGFOOD_BUILD) { + if (sLogsDirectory == null || !ENABLED) { return true; } switch (msg.what) { diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index 68012c4ba..42926fa3e 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -158,7 +158,7 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { } } callbacks.bindAppsAdded(addedWorkspaceScreensFinal, - addNotAnimated, addAnimated, null); + addNotAnimated, addAnimated); } }); } diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java index 9b4510fca..d5b5aa7cf 100644 --- a/src/com/android/launcher3/model/BaseModelUpdateTask.java +++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java @@ -26,6 +26,7 @@ import com.android.launcher3.LauncherModel.CallbackTask; import com.android.launcher3.LauncherModel.Callbacks; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.MultiHashMap; import java.util.ArrayList; @@ -94,19 +95,12 @@ public abstract class BaseModelUpdateTask implements ModelUpdateTask { public void bindUpdatedShortcuts( - ArrayList<ShortcutInfo> updatedShortcuts, UserHandle user) { - bindUpdatedShortcuts(updatedShortcuts, new ArrayList<ShortcutInfo>(), user); - } - - public void bindUpdatedShortcuts( - final ArrayList<ShortcutInfo> updatedShortcuts, - final ArrayList<ShortcutInfo> removedShortcuts, - final UserHandle user) { - if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) { + final ArrayList<ShortcutInfo> updatedShortcuts, final UserHandle user) { + if (!updatedShortcuts.isEmpty()) { scheduleCallbackTask(new CallbackTask() { @Override public void execute(Callbacks callbacks) { - callbacks.bindShortcutsChanged(updatedShortcuts, removedShortcuts, user); + callbacks.bindShortcutsChanged(updatedShortcuts, user); } }); } @@ -132,4 +126,16 @@ public abstract class BaseModelUpdateTask implements ModelUpdateTask { } }); } + + public void deleteAndBindComponentsRemoved(final ItemInfoMatcher matcher) { + getModelWriter().deleteItemsFromDatabase(matcher); + + // Call the components-removed callback + scheduleCallbackTask(new CallbackTask() { + @Override + public void execute(Callbacks callbacks) { + callbacks.bindWorkspaceComponentsRemoved(matcher); + } + }); + } } diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java index 8597e1048..7a27741c3 100644 --- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java +++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java @@ -77,7 +77,7 @@ public class CacheDataUpdatedTask extends BaseModelUpdateTask { scheduleCallbackTask(new CallbackTask() { @Override public void execute(Callbacks callbacks) { - callbacks.bindAppsUpdated(updatedApps); + callbacks.bindAppsAddedOrUpdated(updatedApps); } }); } diff --git a/src/com/android/launcher3/model/LoaderResults.java b/src/com/android/launcher3/model/LoaderResults.java index 0df8b6fee..b7a6b68e8 100644 --- a/src/com/android/launcher3/model/LoaderResults.java +++ b/src/com/android/launcher3/model/LoaderResults.java @@ -122,7 +122,7 @@ public class LoaderResults { filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems, otherWorkspaceItems); - filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets, + filterCurrentWorkspaceItems(currentScreenId, appWidgets, currentAppWidgets, otherAppWidgets); sortWorkspaceItemsSpatially(currentWorkspaceItems); sortWorkspaceItemsSpatially(otherWorkspaceItems); @@ -208,12 +208,12 @@ public class LoaderResults { /** Filters the set of items who are directly or indirectly (via another container) on the * specified screen. */ - private void filterCurrentWorkspaceItems(long currentScreenId, - ArrayList<ItemInfo> allWorkspaceItems, - ArrayList<ItemInfo> currentScreenItems, - ArrayList<ItemInfo> otherScreenItems) { + private <T extends ItemInfo> void filterCurrentWorkspaceItems(long currentScreenId, + ArrayList<T> allWorkspaceItems, + ArrayList<T> currentScreenItems, + ArrayList<T> otherScreenItems) { // Purge any null ItemInfos - Iterator<ItemInfo> iter = allWorkspaceItems.iterator(); + Iterator<T> iter = allWorkspaceItems.iterator(); while (iter.hasNext()) { ItemInfo i = iter.next(); if (i == null) { @@ -224,14 +224,14 @@ public class LoaderResults { // Order the set of items by their containers first, this allows use to walk through the // list sequentially, build up a list of containers that are in the specified screen, // as well as all items in those containers. - Set<Long> itemsOnScreen = new HashSet<Long>(); + Set<Long> itemsOnScreen = new HashSet<>(); Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() { @Override public int compare(ItemInfo lhs, ItemInfo rhs) { return Utilities.longCompare(lhs.container, rhs.container); } }); - for (ItemInfo info : allWorkspaceItems) { + for (T info : allWorkspaceItems) { if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { if (info.screenId == currentScreenId) { currentScreenItems.add(info); @@ -253,23 +253,6 @@ public class LoaderResults { } } - /** Filters the set of widgets which are on the specified screen. */ - private void filterCurrentAppWidgets(long currentScreenId, - ArrayList<LauncherAppWidgetInfo> appWidgets, - ArrayList<LauncherAppWidgetInfo> currentScreenWidgets, - ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) { - - for (LauncherAppWidgetInfo widget : appWidgets) { - if (widget == null) continue; - if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && - widget.screenId == currentScreenId) { - currentScreenWidgets.add(widget); - } else { - otherScreenWidgets.add(widget); - } - } - } - /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to * right) */ private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) { @@ -322,7 +305,7 @@ public class LoaderResults { public void run() { Callbacks callbacks = mCallbacks.get(); if (callbacks != null) { - callbacks.bindItems(workspaceItems, start, start+chunkSize, false); + callbacks.bindItems(workspaceItems.subList(start, start+chunkSize), false); } } }; @@ -332,12 +315,12 @@ public class LoaderResults { // Bind the widgets, one at a time N = appWidgets.size(); for (int i = 0; i < N; i++) { - final LauncherAppWidgetInfo widget = appWidgets.get(i); + final ItemInfo widget = appWidgets.get(i); final Runnable r = new Runnable() { public void run() { Callbacks callbacks = mCallbacks.get(); if (callbacks != null) { - callbacks.bindAppWidget(widget); + callbacks.bindItems(Collections.singletonList(widget), false); } } }; diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 1b2f8d63f..6c78d5bfc 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -43,6 +43,7 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.ItemInfoMatcher; +import com.android.launcher3.util.LongArrayMap; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; @@ -147,55 +148,32 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { break; } - ArrayList<AppInfo> added = null; - ArrayList<AppInfo> modified = null; - final ArrayList<AppInfo> removedApps = new ArrayList<>(); + final ArrayList<AppInfo> addedOrModified = new ArrayList<>(); + addedOrModified.addAll(appsList.added); + appsList.added.clear(); + addedOrModified.addAll(appsList.modified); + appsList.modified.clear(); - if (appsList.added.size() > 0) { - added = new ArrayList<>(appsList.added); - appsList.added.clear(); - } - if (appsList.modified.size() > 0) { - modified = new ArrayList<>(appsList.modified); - appsList.modified.clear(); - } - if (appsList.removed.size() > 0) { - removedApps.addAll(appsList.removed); - appsList.removed.clear(); - } + final ArrayList<AppInfo> removedApps = new ArrayList<>(appsList.removed); + appsList.removed.clear(); final ArrayMap<ComponentName, AppInfo> addedOrUpdatedApps = new ArrayMap<>(); - - if (added != null) { - final ArrayList<AppInfo> addedApps = added; + if (!addedOrModified.isEmpty()) { scheduleCallbackTask(new CallbackTask() { @Override public void execute(Callbacks callbacks) { - callbacks.bindAppsAdded(null, null, null, addedApps); + callbacks.bindAppsAddedOrUpdated(addedOrModified); } }); - for (AppInfo ai : added) { + for (AppInfo ai : addedOrModified) { addedOrUpdatedApps.put(ai.componentName, ai); } } - if (modified != null) { - final ArrayList<AppInfo> modifiedFinal = modified; - for (AppInfo ai : modified) { - addedOrUpdatedApps.put(ai.componentName, ai); - } - scheduleCallbackTask(new CallbackTask() { - @Override - public void execute(Callbacks callbacks) { - callbacks.bindAppsUpdated(modifiedFinal); - } - }); - } - // Update shortcut infos if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) { final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>(); - final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<>(); + final LongArrayMap<Boolean> removedShortcuts = new LongArrayMap<>(); final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<>(); synchronized (dataModel) { @@ -236,7 +214,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { } if ((intent == null) || (appInfo == null)) { - removedShortcuts.add(si); + removedShortcuts.put(si.id, true); continue; } si.intent = intent; @@ -290,9 +268,9 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { } } - bindUpdatedShortcuts(updatedShortcuts, removedShortcuts, mUser); + bindUpdatedShortcuts(updatedShortcuts, mUser); if (!removedShortcuts.isEmpty()) { - getModelWriter().deleteItemsFromDatabase(removedShortcuts); + deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts, false)); } if (!widgets.isEmpty()) { @@ -329,22 +307,12 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { } if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) { - getModelWriter().deleteItemsFromDatabase( - ItemInfoMatcher.ofPackages(removedPackages, mUser)); - getModelWriter().deleteItemsFromDatabase( - ItemInfoMatcher.ofComponents(removedComponents, mUser)); + ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser) + .or(ItemInfoMatcher.ofComponents(removedComponents, mUser)); + deleteAndBindComponentsRemoved(removeMatch); // Remove any queued items from the install queue InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser); - - // Call the components-removed callback - scheduleCallbackTask(new CallbackTask() { - @Override - public void execute(Callbacks callbacks) { - callbacks.bindWorkspaceComponentsRemoved( - removedPackages, removedComponents, mUser); - } - }); } if (!removedApps.isEmpty()) { diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java index 17cc238d4..c1f33a6b2 100644 --- a/src/com/android/launcher3/model/ShortcutsChangedTask.java +++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java @@ -26,9 +26,12 @@ import com.android.launcher3.ShortcutInfo; import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.ShortcutInfoCompat; +import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.MultiHashMap; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; /** @@ -56,33 +59,35 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask { deepShortcutManager.onShortcutsChanged(mShortcuts); // Find ShortcutInfo's that have changed on the workspace. - final ArrayList<ShortcutInfo> removedShortcutInfos = new ArrayList<>(); - MultiHashMap<String, ShortcutInfo> idsToWorkspaceShortcutInfos = new MultiHashMap<>(); + HashSet<ShortcutKey> removedKeys = new HashSet<>(); + MultiHashMap<ShortcutKey, ShortcutInfo> keyToShortcutInfo = new MultiHashMap<>(); + HashSet<String> allIds = new HashSet<>(); + for (ItemInfo itemInfo : dataModel.itemsIdMap) { if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { ShortcutInfo si = (ShortcutInfo) itemInfo; - if (si.getIntent().getPackage().equals(mPackageName) - && si.user.equals(mUser)) { - idsToWorkspaceShortcutInfos.addToList(si.getDeepShortcutId(), si); + if (si.getIntent().getPackage().equals(mPackageName) && si.user.equals(mUser)) { + keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si); + allIds.add(si.getDeepShortcutId()); } } } final ArrayList<ShortcutInfo> updatedShortcutInfos = new ArrayList<>(); - if (!idsToWorkspaceShortcutInfos.isEmpty()) { + if (!keyToShortcutInfo.isEmpty()) { // Update the workspace to reflect the changes to updated shortcuts residing on it. List<ShortcutInfoCompat> shortcuts = deepShortcutManager.queryForFullDetails( - mPackageName, new ArrayList<>(idsToWorkspaceShortcutInfos.keySet()), mUser); + mPackageName, new ArrayList<>(allIds), mUser); for (ShortcutInfoCompat fullDetails : shortcuts) { - List<ShortcutInfo> shortcutInfos = idsToWorkspaceShortcutInfos - .remove(fullDetails.getId()); + ShortcutKey key = ShortcutKey.fromInfo(fullDetails); + List<ShortcutInfo> shortcutInfos = keyToShortcutInfo.remove(key); if (!fullDetails.isPinned()) { // The shortcut was previously pinned but is no longer, so remove it from // the workspace and our pinned shortcut counts. // Note that we put this check here, after querying for full details, // because there's a possible race condition between pinning and // receiving this callback. - removedShortcutInfos.addAll(shortcutInfos); + removedKeys.add(key); continue; } for (final ShortcutInfo shortcutInfo : shortcutInfos) { @@ -94,16 +99,14 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask { } } - // If there are still entries in idsToWorkspaceShortcutInfos, that means that + // If there are still entries in keyToShortcutInfo, that means that // the corresponding shortcuts weren't passed in onShortcutsChanged(). This // means they were cleared, so we remove and unpin them now. - for (String id : idsToWorkspaceShortcutInfos.keySet()) { - removedShortcutInfos.addAll(idsToWorkspaceShortcutInfos.get(id)); - } + removedKeys.addAll(keyToShortcutInfo.keySet()); - bindUpdatedShortcuts(updatedShortcutInfos, removedShortcutInfos, mUser); - if (!removedShortcutInfos.isEmpty()) { - getModelWriter().deleteItemsFromDatabase(removedShortcutInfos); + bindUpdatedShortcuts(updatedShortcutInfos, mUser); + if (!keyToShortcutInfo.isEmpty()) { + deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(removedKeys)); } if (mUpdateIdMap) { diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java index 802771f04..8170f9a67 100644 --- a/src/com/android/launcher3/model/UserLockStateChangedTask.java +++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java @@ -29,9 +29,11 @@ import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.ShortcutInfoCompat; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.ItemInfoMatcher; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -70,17 +72,19 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask { // Update the workspace to reflect the changes to updated shortcuts residing on it. ArrayList<ShortcutInfo> updatedShortcutInfos = new ArrayList<>(); - ArrayList<ShortcutInfo> deletedShortcutInfos = new ArrayList<>(); + HashSet<ShortcutKey> removedKeys = new HashSet<>(); + for (ItemInfo itemInfo : dataModel.itemsIdMap) { if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT && mUser.equals(itemInfo.user)) { ShortcutInfo si = (ShortcutInfo) itemInfo; if (isUserUnlocked) { - ShortcutInfoCompat shortcut = pinnedShortcuts.get(ShortcutKey.fromItemInfo(si)); + ShortcutKey key = ShortcutKey.fromItemInfo(si); + ShortcutInfoCompat shortcut = pinnedShortcuts.get(key); // We couldn't verify the shortcut during loader. If its no longer available // (probably due to clear data), delete the workspace item as well if (shortcut == null) { - deletedShortcutInfos.add(si); + removedKeys.add(key); continue; } si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_LOCKED_USER; @@ -93,9 +97,9 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask { updatedShortcutInfos.add(si); } } - bindUpdatedShortcuts(updatedShortcutInfos, deletedShortcutInfos, mUser); - if (!deletedShortcutInfos.isEmpty()) { - getModelWriter().deleteItemsFromDatabase(deletedShortcutInfos); + bindUpdatedShortcuts(updatedShortcutInfos, mUser); + if (!removedKeys.isEmpty()) { + deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(removedKeys)); } // Remove shortcut id map for that user diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java index 73d89aa18..6a7098915 100644 --- a/src/com/android/launcher3/notification/NotificationListener.java +++ b/src/com/android/launcher3/notification/NotificationListener.java @@ -30,15 +30,20 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Pair; + import com.android.launcher3.LauncherModel; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.util.SettingsObserver; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; +import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING; + /** * A {@link NotificationListenerService} that sends updates to its * {@link NotificationsChangedListener} when notifications are posted or canceled, @@ -57,12 +62,14 @@ public class NotificationListener extends NotificationListenerService { private static NotificationListener sNotificationListenerInstance = null; private static NotificationsChangedListener sNotificationsChangedListener; private static boolean sIsConnected; + private static boolean sIsCreated; private final Handler mWorkerHandler; private final Handler mUiHandler; - private final Ranking mTempRanking = new Ranking(); + private SettingsObserver mNotificationBadgingObserver; + private final Handler.Callback mWorkerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message message) { @@ -77,7 +84,7 @@ public class NotificationListener extends NotificationListenerService { List<StatusBarNotification> activeNotifications; if (sIsConnected) { try { - activeNotifications = filterNotifications(getActiveNotifications()); + activeNotifications = filterNotifications(getActiveNotifications()); } catch (SecurityException ex) { Log.e(TAG, "SecurityException: failed to fetch notifications"); activeNotifications = new ArrayList<StatusBarNotification>(); @@ -130,6 +137,28 @@ public class NotificationListener extends NotificationListenerService { sNotificationListenerInstance = this; } + @Override + public void onCreate() { + super.onCreate(); + sIsCreated = true; + mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) { + @Override + public void onSettingChanged(boolean isNotificationBadgingEnabled) { + if (!isNotificationBadgingEnabled) { + requestUnbind(); + } + } + }; + mNotificationBadgingObserver.register(NOTIFICATION_BADGING); + } + + @Override + public void onDestroy() { + super.onDestroy(); + sIsCreated = false; + mNotificationBadgingObserver.unregister(); + } + public static @Nullable NotificationListener getInstanceIfConnected() { return sIsConnected ? sNotificationListenerInstance : null; } @@ -143,6 +172,11 @@ public class NotificationListener extends NotificationListenerService { NotificationListener notificationListener = getInstanceIfConnected(); if (notificationListener != null) { notificationListener.onNotificationFullRefresh(); + } else if (!sIsCreated && sNotificationsChangedListener != null) { + // User turned off badging globally, so we unbound this service; + // tell the listener that there are no notifications to remove dots. + sNotificationsChangedListener.onNotificationFullRefresh( + Collections.<StatusBarNotification>emptyList()); } } @@ -205,7 +239,7 @@ public class NotificationListener extends NotificationListenerService { .getActiveNotifications(NotificationKeyData.extractKeysOnly(keys) .toArray(new String[keys.size()])); return notifications == null - ? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications); + ? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications); } /** diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java index 42de28466..18787b6a2 100644 --- a/src/com/android/launcher3/util/ItemInfoMatcher.java +++ b/src/com/android/launcher3/util/ItemInfoMatcher.java @@ -18,6 +18,7 @@ package com.android.launcher3.util; import android.content.ComponentName; import android.os.UserHandle; +import android.util.SparseLongArray; import com.android.launcher3.FolderInfo; import com.android.launcher3.ItemInfo; @@ -66,6 +67,32 @@ public abstract class ItemInfoMatcher { return filtered; } + /** + * Returns a new matcher with returns true if either this or {@param matcher} returns true. + */ + public ItemInfoMatcher or(final ItemInfoMatcher matcher) { + final ItemInfoMatcher that = this; + return new ItemInfoMatcher() { + @Override + public boolean matches(ItemInfo info, ComponentName cn) { + return that.matches(info, cn) || matcher.matches(info, cn); + } + }; + } + + /** + * Returns a new matcher with returns true if both this and {@param matcher} returns true. + */ + public ItemInfoMatcher and(final ItemInfoMatcher matcher) { + final ItemInfoMatcher that = this; + return new ItemInfoMatcher() { + @Override + public boolean matches(ItemInfo info, ComponentName cn) { + return that.matches(info, cn) && matcher.matches(info, cn); + } + }; + } + public static ItemInfoMatcher ofUser(final UserHandle user) { return new ItemInfoMatcher() { @Override @@ -104,4 +131,14 @@ public abstract class ItemInfoMatcher { } }; } + + public static ItemInfoMatcher ofItemIds( + final LongArrayMap<Boolean> ids, final Boolean matchDefault) { + return new ItemInfoMatcher() { + @Override + public boolean matches(ItemInfo info, ComponentName cn) { + return ids.get(info.id, matchDefault); + } + }; + } } diff --git a/src/com/android/launcher3/util/RunnableWithId.java b/src/com/android/launcher3/util/RunnableWithId.java new file mode 100644 index 000000000..030eb09ff --- /dev/null +++ b/src/com/android/launcher3/util/RunnableWithId.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.util; + +/** + * A runnable with an id associated which is used for equality check. + */ +public abstract class RunnableWithId implements Runnable { + + public static final int RUNNABLE_ID_BIND_APPS = 1; + public static final int RUNNABLE_ID_BIND_WIDGETS = 2; + + public final int id; + + public RunnableWithId(int id) { + this.id = id; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof RunnableWithId && ((RunnableWithId) obj).id == id; + } +} diff --git a/src/com/android/launcher3/util/SettingsObserver.java b/src/com/android/launcher3/util/SettingsObserver.java new file mode 100644 index 000000000..6baa24293 --- /dev/null +++ b/src/com/android/launcher3/util/SettingsObserver.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.util; + +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings; + +public interface SettingsObserver { + + /** + * Registers the content observer to call {@link #onSettingChanged(boolean)} when any of the + * passed settings change. The value passed to onSettingChanged() is based on the key setting. + */ + void register(String keySetting, String ... dependentSettings); + void unregister(); + void onSettingChanged(boolean keySettingEnabled); + + + abstract class Secure extends ContentObserver implements SettingsObserver { + private ContentResolver mResolver; + private String mKeySetting; + + public Secure(ContentResolver resolver) { + super(new Handler()); + mResolver = resolver; + } + + @Override + public void register(String keySetting, String ... dependentSettings) { + mKeySetting = keySetting; + mResolver.registerContentObserver( + Settings.Secure.getUriFor(mKeySetting), false, this); + for (String setting : dependentSettings) { + mResolver.registerContentObserver( + Settings.Secure.getUriFor(setting), false, this); + } + onChange(true); + } + + @Override + public void unregister() { + mResolver.unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + onSettingChanged(Settings.Secure.getInt(mResolver, mKeySetting, 1) == 1); + } + } + + abstract class System extends ContentObserver implements SettingsObserver { + private ContentResolver mResolver; + private String mKeySetting; + + public System(ContentResolver resolver) { + super(new Handler()); + mResolver = resolver; + } + + @Override + public void register(String keySetting, String ... dependentSettings) { + mKeySetting = keySetting; + mResolver.registerContentObserver( + Settings.System.getUriFor(mKeySetting), false, this); + for (String setting : dependentSettings) { + mResolver.registerContentObserver( + Settings.System.getUriFor(setting), false, this); + } + onChange(true); + } + + @Override + public void unregister() { + mResolver.unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + onSettingChanged(Settings.System.getInt(mResolver, mKeySetting, 1) == 1); + } + } +} diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java index 6b5b095c7..d7a2625e9 100644 --- a/src/com/android/launcher3/util/SystemUiController.java +++ b/src/com/android/launcher3/util/SystemUiController.java @@ -30,6 +30,7 @@ public class SystemUiController { public static final int UI_STATE_BASE_WINDOW = 0; public static final int UI_STATE_ALL_APPS = 1; public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2; + public static final int UI_STATE_ROOT_VIEW = 3; public static final int FLAG_LIGHT_NAV = 1 << 0; public static final int FLAG_DARK_NAV = 1 << 1; @@ -37,7 +38,7 @@ public class SystemUiController { public static final int FLAG_DARK_STATUS = 1 << 3; private final Window mWindow; - private final int[] mStates = new int[3]; + private final int[] mStates = new int[4]; public SystemUiController(Window window) { mWindow = window; diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java index 4cb6ca831..e5c1dd1b4 100644 --- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java +++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java @@ -16,11 +16,13 @@ package com.android.launcher3.util; +import android.os.Process; import android.view.View; import android.view.View.OnAttachStateChangeListener; import android.view.ViewTreeObserver.OnDrawListener; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherModel; import java.util.ArrayList; import java.util.concurrent.Executor; @@ -37,6 +39,7 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, private Launcher mLauncher; private View mAttachedView; private boolean mCompleted; + private boolean mIsExecuting; private boolean mLoadAnimationCompleted; private boolean mFirstDrawCompleted; @@ -62,6 +65,7 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, @Override public void execute(Runnable command) { mTasks.add(command); + LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_BACKGROUND); } @Override @@ -78,6 +82,13 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, mAttachedView.post(this); } + /** + * Returns whether the executor is still queuing tasks and hasn't yet executed them. + */ + public boolean canQueue() { + return !mIsExecuting && !mCompleted; + } + public void onLoadAnimationCompleted() { mLoadAnimationCompleted = true; if (mAttachedView != null) { @@ -89,6 +100,7 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, public void run() { // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called. if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) { + mIsExecuting = true; for (final Runnable r : mTasks) { mExecutor.execute(r); } @@ -99,6 +111,7 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, public void markCompleted() { mTasks.clear(); mCompleted = true; + mIsExecuting = false; if (mAttachedView != null) { mAttachedView.getViewTreeObserver().removeOnDrawListener(this); mAttachedView.removeOnAttachStateChangeListener(this); @@ -106,5 +119,6 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable, if (mLauncher != null) { mLauncher.clearPendingExecutor(this); } + LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_DEFAULT); } } diff --git a/src/com/android/launcher3/views/ButtonPreference.java b/src/com/android/launcher3/views/ButtonPreference.java index 4697e25e4..fdcf2ca5b 100644 --- a/src/com/android/launcher3/views/ButtonPreference.java +++ b/src/com/android/launcher3/views/ButtonPreference.java @@ -28,7 +28,7 @@ import android.view.ViewGroup; */ public class ButtonPreference extends Preference { - private View.OnClickListener mClickListener; + private boolean mWidgetFrameVisible = false; public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); @@ -46,9 +46,9 @@ public class ButtonPreference extends Preference { super(context); } - public void setButtonOnClickListener(View.OnClickListener clickListener) { - if (mClickListener != clickListener) { - mClickListener = clickListener; + public void setWidgetFrameVisible(boolean isVisible) { + if (mWidgetFrameVisible != isVisible) { + mWidgetFrameVisible = isVisible; notifyChanged(); } } @@ -59,12 +59,7 @@ public class ButtonPreference extends Preference { ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame); if (widgetFrame != null) { - View button = widgetFrame.getChildAt(0); - if (button != null) { - button.setOnClickListener(mClickListener); - } - widgetFrame.setVisibility( - (mClickListener == null || button == null) ? View.GONE : View.VISIBLE); + widgetFrame.setVisibility(mWidgetFrameVisible ? View.VISIBLE : View.GONE); } } } diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 0b4bf628e..01101ac74 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -88,7 +88,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab mScrollInterpolator = new SwipeDetector.ScrollInterpolator(); mInsets = new Rect(); mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL); - mGradientBackground = (GradientView) mLauncher.findViewById(R.id.gradient_bg); + mGradientBackground = (GradientView) mLauncher.getLayoutInflater().inflate( + R.layout.gradient_bg, mLauncher.getDragLayer(), false); } @Override @@ -106,6 +107,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab onWidgetsBound(); + mLauncher.getDragLayer().addView(mGradientBackground); + mGradientBackground.setVisibility(VISIBLE); mLauncher.getDragLayer().addView(this); measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); setTranslationY(mTranslationYClosed); @@ -212,11 +215,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mIsOpen = false; mSwipeDetector.finishedScrolling(); - ((ViewGroup) getParent()).removeView(WidgetsBottomSheet.this); - mLauncher.getSystemUiController().updateUiState( - SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0); + onCloseComplete(); } }); mOpenCloseAnimator.setInterpolator(mSwipeDetector.isIdleState() @@ -224,12 +224,18 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab mOpenCloseAnimator.start(); } else { setTranslationY(mTranslationYClosed); - mLauncher.getSystemUiController().updateUiState( - SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0); - mIsOpen = false; + onCloseComplete(); } } + private void onCloseComplete() { + mIsOpen = false; + mLauncher.getDragLayer().removeView(mGradientBackground); + mLauncher.getDragLayer().removeView(WidgetsBottomSheet.this); + mLauncher.getSystemUiController().updateUiState( + SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0); + } + @Override protected boolean isOfType(@FloatingViewType int type) { return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0; |