diff options
Diffstat (limited to 'src/com/android/launcher3')
92 files changed, 1447 insertions, 2140 deletions
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index 597e93703..49968189b 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -25,6 +25,8 @@ import android.view.View; import android.widget.LinearLayout; import com.android.launcher3.dragndrop.DragLayer; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.util.TouchController; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -32,18 +34,20 @@ import java.lang.annotation.RetentionPolicy; /** * Base class for a View which shows a floating UI on top of the launcher UI. */ -public abstract class AbstractFloatingView extends LinearLayout { +public abstract class AbstractFloatingView extends LinearLayout implements TouchController { @IntDef(flag = true, value = { TYPE_FOLDER, TYPE_POPUP_CONTAINER_WITH_ARROW, - TYPE_WIDGETS_BOTTOM_SHEET + TYPE_WIDGETS_BOTTOM_SHEET, + TYPE_WIDGET_RESIZE_FRAME }) @Retention(RetentionPolicy.SOURCE) public @interface FloatingViewType {} public static final int TYPE_FOLDER = 1 << 0; public static final int TYPE_POPUP_CONTAINER_WITH_ARROW = 1 << 1; public static final int TYPE_WIDGETS_BOTTOM_SHEET = 1 << 2; + public static final int TYPE_WIDGET_RESIZE_FRAME = 1 << 3; protected boolean mIsOpen; @@ -72,21 +76,7 @@ public abstract class AbstractFloatingView extends LinearLayout { protected abstract void handleClose(boolean animate); - /** - * If the view is current handling keyboard, return the active target, null otherwise - */ - public ExtendedEditText getActiveTextView() { - return null; - } - - - /** - * Any additional view (outside of this container) where touch should be allowed while this - * view is visible. - */ - public View getExtendedTouchView() { - return null; - } + public abstract void logActionCommand(int command); public final boolean isOpen() { return mIsOpen; @@ -97,6 +87,16 @@ public abstract class AbstractFloatingView extends LinearLayout { protected abstract boolean isOfType(@FloatingViewType int type); + public void onBackPressed() { + logActionCommand(Action.Command.BACK); + close(true); + } + + @Override + public boolean onControllerTouchEvent(MotionEvent ev) { + return false; + } + protected static <T extends AbstractFloatingView> T getOpenView( Launcher launcher, @FloatingViewType int type) { DragLayer dragLayer = launcher.getDragLayer(); @@ -139,8 +139,6 @@ public abstract class AbstractFloatingView extends LinearLayout { public static AbstractFloatingView getTopOpenView(Launcher launcher) { return getOpenView(launcher, TYPE_FOLDER | TYPE_POPUP_CONTAINER_WITH_ARROW - | TYPE_WIDGETS_BOTTOM_SHEET); + | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME); } - - public abstract int getLogContainerType(); } diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java index 3da199635..7d2f75385 100644 --- a/src/com/android/launcher3/AppInfo.java +++ b/src/com/android/launcher3/AppInfo.java @@ -19,6 +19,7 @@ package com.android.launcher3; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.os.UserHandle; @@ -31,6 +32,10 @@ import com.android.launcher3.util.PackageManagerHelper; */ public class AppInfo extends ItemInfoWithIcon { + public static final int FLAG_SYSTEM_UNKNOWN = 0; + public static final int FLAG_SYSTEM_YES = 1 << 0; + public static final int FLAG_SYSTEM_NO = 1 << 1; + /** * The intent used to start the application. */ @@ -43,6 +48,11 @@ public class AppInfo extends ItemInfoWithIcon { */ public int isDisabled = ShortcutInfo.DEFAULT; + /** + * Stores if the app is a system app or not. + */ + public int isSystemApp; + public AppInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; } @@ -71,6 +81,10 @@ public class AppInfo extends ItemInfoWithIcon { } intent = makeLaunchIntent(info); + + isSystemApp = (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0 + ? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES; + } public AppInfo(AppInfo info) { @@ -79,6 +93,7 @@ public class AppInfo extends ItemInfoWithIcon { title = Utilities.trim(info.title); intent = new Intent(info.intent); isDisabled = info.isDisabled; + isSystemApp = info.isSystemApp; } @Override diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index a486a3aa3..1e95333ff 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -8,22 +8,19 @@ import android.animation.ValueAnimator.AnimatorUpdateListener; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; -import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.widget.FrameLayout; +import android.view.ViewGroup; import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.util.FocusLogic; -import com.android.launcher3.util.TouchController; -public class AppWidgetResizeFrame extends FrameLayout - implements View.OnKeyListener, TouchController { +public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener { private static final int SNAP_DURATION = 150; private static final float DIMMED_HANDLE_ALPHA = 0f; private static final float RESIZE_THRESHOLD = 0.66f; @@ -109,12 +106,28 @@ public class AppWidgetResizeFrame extends FrameLayout protected void onFinishInflate() { super.onFinishInflate(); + ViewGroup content = (ViewGroup) getChildAt(0); for (int i = 0; i < HANDLE_COUNT; i ++) { - mDragHandles[i] = getChildAt(i); + mDragHandles[i] = content.getChildAt(i); } } - public void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout, + public static void showForWidget(LauncherAppWidgetHostView widget, CellLayout cellLayout) { + Launcher launcher = Launcher.getLauncher(cellLayout.getContext()); + AbstractFloatingView.closeAllOpenViews(launcher); + + DragLayer dl = launcher.getDragLayer(); + AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater() + .inflate(R.layout.app_widget_resize_frame, dl, false); + frame.setupForWidget(widget, cellLayout, dl); + ((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true; + + dl.addView(frame); + frame.mIsOpen = true; + frame.snapToWidget(false); + } + + private void setupForWidget(LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) { mCellLayout = cellLayout; mWidgetView = widgetView; @@ -126,14 +139,8 @@ public class AppWidgetResizeFrame extends FrameLayout mMinHSpan = info.minSpanX; mMinVSpan = info.minSpanY; - if (!info.isCustomWidget) { - mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(), - widgetView.getAppWidgetInfo().provider, null); - } else { - Resources r = getContext().getResources(); - int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding); - mWidgetPadding = new Rect(padding, padding, padding, padding); - } + mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(getContext(), + widgetView.getAppWidgetInfo().provider, null); if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) { mDragHandles[INDEX_TOP].setVisibility(GONE); @@ -391,7 +398,7 @@ public class AppWidgetResizeFrame extends FrameLayout out.bottom = out.top + height; } - public void snapToWidget(boolean animate) { + private void snapToWidget(boolean animate) { getSnappedRectRelativeToDragLayer(sTmpRect); int newWidth = sTmpRect.width(); int newHeight = sTmpRect.height(); @@ -455,7 +462,7 @@ public class AppWidgetResizeFrame extends FrameLayout public boolean onKey(View v, int keyCode, KeyEvent event) { // Clear the frame and give focus to the widget host view when a directional key is pressed. if (FocusLogic.shouldConsume(keyCode)) { - mDragLayer.clearResizeFrame(); + close(false); mWidgetView.requestFocus(); return true; } @@ -505,9 +512,25 @@ public class AppWidgetResizeFrame extends FrameLayout if (ev.getAction() == MotionEvent.ACTION_DOWN && handleTouchDown(ev)) { return true; } + close(false); return false; } + @Override + protected void handleClose(boolean animate) { + mDragLayer.removeView(this); + } + + @Override + public void logActionCommand(int command) { + // TODO: Log this case. + } + + @Override + protected boolean isOfType(int type) { + return (type & TYPE_WIDGET_RESIZE_FRAME) != 0; + } + /** * A mutable class for describing the range of two int values. */ diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index d82579bf7..162aa0889 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -28,7 +28,9 @@ import android.content.res.XmlResourceParser; import android.database.sqlite.SQLiteDatabase; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; +import android.os.Process; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; @@ -433,8 +435,10 @@ public class AutoInstallsLayout { return -1; } - mValues.put(LauncherSettings.Favorites.ICON, - Utilities.flattenBitmap(LauncherIcons.createIconBitmap(icon, mContext))); + // Auto installs should always support the current platform version. + mValues.put(LauncherSettings.Favorites.ICON, Utilities.flattenBitmap( + LauncherIcons.createBadgedIconBitmap( + icon, Process.myUserHandle(), mContext, Build.VERSION.SDK_INT))); mValues.put(Favorites.ICON_PACKAGE, mIconRes.getResourcePackageName(iconId)); mValues.put(Favorites.ICON_RESOURCE, mIconRes.getResourceName(iconId)); diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index ac842f92e..485125e03 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -496,11 +496,17 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver { public PreloadIconDrawable applyProgressLevel(int progressLevel) { if (getTag() instanceof ItemInfoWithIcon) { ItemInfoWithIcon info = (ItemInfoWithIcon) getTag(); - setContentDescription(progressLevel > 0 - ? getContext().getString(R.string.app_downloading_title, info.title, - NumberFormat.getPercentInstance().format(progressLevel * 0.01)) - : getContext().getString(R.string.app_waiting_download_title, info.title)); - + if (progressLevel >= 100) { + setContentDescription(info.contentDescription != null + ? info.contentDescription : ""); + } else if (progressLevel > 0) { + setContentDescription(getContext() + .getString(R.string.app_downloading_title, info.title, + NumberFormat.getPercentInstance().format(progressLevel * 0.01))); + } else { + setContentDescription(getContext() + .getString(R.string.app_waiting_download_title, info.title)); + } if (mIcon != null) { final PreloadIconDrawable preloadDrawable; if (mIcon instanceof PreloadIconDrawable) { diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java index 632e49059..375930062 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -178,7 +178,7 @@ public abstract class ButtonDropTarget extends TextView @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { - mActive = supportsDrop(dragObject.dragSource, dragObject.dragInfo); + mActive = supportsDrop(dragObject.dragInfo); mDrawable.setColorFilter(null); if (mCurrentColorAnim != null) { mCurrentColorAnim.cancel(); @@ -194,10 +194,10 @@ public abstract class ButtonDropTarget extends TextView @Override public final boolean acceptDrop(DragObject dragObject) { - return supportsDrop(dragObject.dragSource, dragObject.dragInfo); + return supportsDrop(dragObject.dragInfo); } - protected abstract boolean supportsDrop(DragSource source, ItemInfo info); + protected abstract boolean supportsDrop(ItemInfo info); @Override public boolean isDropEnabled() { diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index f83574808..d92b934d1 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -355,10 +355,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint); } - public void buildHardwareLayer() { - mShortcutsAndWidgets.buildLayer(); - } - public void setCellDimensions(int width, int height) { mFixedCellWidth = mCellWidth = width; mFixedCellHeight = mCellHeight = height; diff --git a/src/com/android/launcher3/CustomAppWidget.java b/src/com/android/launcher3/CustomAppWidget.java deleted file mode 100644 index 1b4ed79c0..000000000 --- a/src/com/android/launcher3/CustomAppWidget.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.android.launcher3; - -public interface CustomAppWidget { - public String getLabel(); - public int getPreviewImage(); - public int getIcon(); - public int getWidgetLayout(); - - public int getSpanX(); - public int getSpanY(); - public int getMinSpanX(); - public int getMinSpanY(); - public int getResizeMode(); -} diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index 4dcb64f01..fdd4f34bd 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -46,7 +46,7 @@ public class DeleteDropTarget extends ButtonDropTarget { @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { super.onDragStart(dragObject, options); - setTextBasedOnDragSource(dragObject.dragSource); + setTextBasedOnDragSource(dragObject.dragInfo); } /** @return true for items that should have a "Remove" action in accessibility. */ @@ -57,16 +57,16 @@ public class DeleteDropTarget extends ButtonDropTarget { } @Override - protected boolean supportsDrop(DragSource source, ItemInfo info) { + protected boolean supportsDrop(ItemInfo info) { return true; } /** - * Set the drop target's text to either "Remove" or "Cancel" depending on the drag source. + * Set the drop target's text to either "Remove" or "Cancel" depending on the drag item. */ - public void setTextBasedOnDragSource(DragSource dragSource) { + private void setTextBasedOnDragSource(ItemInfo item) { if (!TextUtils.isEmpty(mText)) { - mText = getResources().getString(dragSource.supportsDeleteDropTarget() + mText = getResources().getString(item.id != ItemInfo.NO_ID ? R.string.remove_drop_target_label : android.R.string.cancel); requestLayout(); diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index dec0a92a9..8f7e8822b 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -277,8 +277,12 @@ public class DeviceProfile { DeviceProfile profile = new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y, isLandscape); - // Hide labels on the workspace. - profile.adjustToHideWorkspaceLabels(); + // If there isn't enough vertical cell padding with the labels displayed, hide the labels. + float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx + - iconDrawablePaddingPx - profile.iconTextSizePx; + if (workspaceCellPaddingY < profile.iconDrawablePaddingPx * 2) { + profile.adjustToHideWorkspaceLabels(); + } // We use these scales to measure and layout the widgets using their full invariant profile // sizes and then draw them scaled and centered to fit in their multi-window mode cellspans. @@ -350,9 +354,18 @@ public class DeviceProfile { iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale); iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale); - cellWidthPx = iconSizePx + iconDrawablePaddingPx; cellHeightPx = iconSizePx + iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx); + int cellYPadding = (getCellSize().y - cellHeightPx) / 2; + if (iconDrawablePaddingPx > cellYPadding && !isVerticalBarLayout() + && !inMultiWindowMode()) { + // Ensures that the label is closer to its corresponding icon. This is not an issue + // with vertical bar layout or multi-window mode since the issue is handled separately + // with their calls to {@link #adjustToHideWorkspaceLabels}. + cellHeightPx -= (iconDrawablePaddingPx - cellYPadding); + iconDrawablePaddingPx = cellYPadding; + } + cellWidthPx = iconSizePx + iconDrawablePaddingPx; // All apps allAppsIconTextSizePx = iconTextSizePx; @@ -755,11 +768,14 @@ public class DeviceProfile { return new int[] { padding.left - mInsets.left, padding.right + mInsets.left}; } + public boolean inMultiWindowMode() { + return this != inv.landscapeProfile && this != inv.portraitProfile; + } + public boolean shouldIgnoreLongPressToOverview(float touchX) { - boolean inMultiWindowMode = this != inv.landscapeProfile && this != inv.portraitProfile; boolean touchedLhsEdge = mInsets.left == 0 && touchX < edgeMarginPx; boolean touchedRhsEdge = mInsets.right == 0 && touchX > (widthPx - edgeMarginPx); - return !inMultiWindowMode && (touchedLhsEdge || touchedRhsEdge); + return !inMultiWindowMode() && (touchedLhsEdge || touchedRhsEdge); } private static Context getContext(Context c, int orientation) { diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java index dcd8f589a..c6106c23e 100644 --- a/src/com/android/launcher3/DragSource.java +++ b/src/com/android/launcher3/DragSource.java @@ -27,22 +27,6 @@ import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider; public interface DragSource extends LogContainerProvider { /** - * @return whether items dragged from this source supports 'App Info' - */ - boolean supportsAppInfoDropTarget(); - - /** - * @return whether items dragged from this source supports 'Delete' drop target (e.g. to remove - * a shortcut.) If this returns false, the drop target will say "Cancel" instead of "Remove." - */ - boolean supportsDeleteDropTarget(); - - /* - * @return the scale of the icons over the workspace icon size - */ - float getIntrinsicIconScaleFactor(); - - /** * A callback made back to the source after an item from this source has been dropped on a * DropTarget. */ diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java index 596aa8f7b..403c8b8ba 100644 --- a/src/com/android/launcher3/ExtendedEditText.java +++ b/src/com/android/launcher3/ExtendedEditText.java @@ -16,12 +16,16 @@ package com.android.launcher3; import android.content.Context; +import android.text.TextUtils; import android.util.AttributeSet; import android.view.DragEvent; import android.view.KeyEvent; +import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import com.android.launcher3.util.UiThreadHelper; + /** * The edit text that reports back when the back key has been pressed. @@ -102,8 +106,7 @@ public class ExtendedEditText extends EditText { } public void dispatchBackKey() { - ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE)) - .hideSoftInputFromWindow(getWindowToken(), 0); + UiThreadHelper.hideKeyboardAsync(getContext(), getWindowToken()); if (mBackKeyListener != null) { mBackKeyListener.onBackKey(); } @@ -121,4 +124,17 @@ public class ExtendedEditText extends EditText { public boolean isSuggestionsEnabled() { return !mForceDisableSuggestions && super.isSuggestionsEnabled(); } + + public void reset() { + if (!TextUtils.isEmpty(getText())) { + setText(""); + } + if (isFocused()) { + View nextFocus = focusSearch(View.FOCUS_DOWN); + if (nextFocus != null) { + nextFocus.requestFocus(); + } + } + UiThreadHelper.hideKeyboardAsync(getContext(), getWindowToken()); + } } diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java index 3cbc989eb..cea7e431a 100644 --- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java +++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java @@ -24,6 +24,7 @@ import android.view.View; import android.view.ViewPropertyAnimator; import android.view.ViewTreeObserver; import com.android.launcher3.util.Thunk; +import com.android.launcher3.util.TraceHelper; /* * This is a helper class that listens to updates from the corresponding animation. @@ -71,15 +72,12 @@ public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter if (sGlobalDrawListener != null) { view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener); } + + TraceHelper.beginSection("TICK"); sGlobalDrawListener = new ViewTreeObserver.OnDrawListener() { - private long mTime = System.currentTimeMillis(); public void onDraw() { sGlobalFrameCounter++; - if (DEBUG) { - long newTime = System.currentTimeMillis(); - Log.d(TAG, "TICK " + (newTime - mTime)); - mTime = newTime; - } + TraceHelper.partitionSection("TICK", "Frame drawn"); } }; view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener); diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index af3abebb4..09f9e827c 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -16,16 +16,9 @@ package com.android.launcher3; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ArgbEvaluator; -import android.animation.ValueAnimator; import android.content.Context; -import android.graphics.Color; import android.graphics.Rect; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -35,11 +28,9 @@ import android.widget.FrameLayout; import android.widget.TextView; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.dynamicui.ExtractedColors; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; -import com.android.launcher3.util.Themes; public class Hotseat extends FrameLayout implements UserEventDispatcher.LogContainerProvider { @@ -51,12 +42,6 @@ public class Hotseat extends FrameLayout @ViewDebug.ExportedProperty(category = "launcher") private final boolean mHasVerticalHotseat; - @ViewDebug.ExportedProperty(category = "launcher") - private int mBackgroundColor; - @ViewDebug.ExportedProperty(category = "launcher") - private ColorDrawable mBackground; - private ValueAnimator mBackgroundColorAnimator; - public Hotseat(Context context) { this(context, null); } @@ -69,12 +54,6 @@ public class Hotseat extends FrameLayout super(context, attrs, defStyle); mLauncher = Launcher.getLauncher(context); mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout(); - mBackgroundColor = ColorUtils.setAlphaComponent( - Themes.getAttrColor(context, android.R.attr.colorPrimary), 0); - mBackground = new ColorDrawable(mBackgroundColor); - if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - setBackground(mBackground); - } } public CellLayout getLayout() { @@ -149,7 +128,6 @@ public class Hotseat extends FrameLayout allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener()); if (mLauncher != null) { mLauncher.setAllAppsButton(allAppsButton); - allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener()); allAppsButton.setOnClickListener(mLauncher); allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler); } @@ -178,49 +156,4 @@ public class Hotseat extends FrameLayout target.gridY = info.cellY; targetParent.containerType = ContainerType.HOTSEAT; } - - public void updateColor(ExtractedColors extractedColors, boolean animate) { - if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - // not hotseat visible - return; - } - if (!mHasVerticalHotseat) { - int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX); - if (mBackgroundColorAnimator != null) { - mBackgroundColorAnimator.cancel(); - } - if (!animate) { - setBackgroundColor(color); - } else { - mBackgroundColorAnimator = ValueAnimator.ofInt(mBackgroundColor, color); - mBackgroundColorAnimator.setEvaluator(new ArgbEvaluator()); - mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mBackground.setColor((Integer) animation.getAnimatedValue()); - } - }); - mBackgroundColorAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mBackgroundColorAnimator = null; - } - }); - mBackgroundColorAnimator.start(); - } - mBackgroundColor = color; - } - } - - public void setBackgroundTransparent(boolean enable) { - if (enable) { - mBackground.setAlpha(0); - } else { - mBackground.setAlpha(255); - } - } - - public int getBackgroundDrawableColor() { - return mBackgroundColor; - } } diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index 6f86954dc..573e8a256 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -123,7 +123,7 @@ public class IconCache { } private Drawable getFullResDefaultActivityIcon() { - return getFullResIcon(Resources.getSystem(), Utilities.isAtLeastO() ? + return getFullResIcon(Resources.getSystem(), Utilities.ATLEAST_OREO ? android.R.drawable.sym_def_app_icon : android.R.mipmap.sym_def_app_icon); } diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java index f919dd052..eb6a7045e 100644 --- a/src/com/android/launcher3/InfoDropTarget.java +++ b/src/com/android/launcher3/InfoDropTarget.java @@ -99,8 +99,8 @@ public class InfoDropTarget extends UninstallDropTarget { } @Override - protected boolean supportsDrop(DragSource source, ItemInfo info) { - return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info); + protected boolean supportsDrop(ItemInfo info) { + return supportsDrop(getContext(), info); } public static boolean supportsDrop(Context context, ItemInfo info) { diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index d7bebd1b1..7a431986d 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -85,7 +85,9 @@ public class InvariantDeviceProfile { * Number of icons inside the hotseat area. */ public int numHotseatIcons; + int defaultLayoutId; + int demoModeLayoutId; public DeviceProfile landscapeProfile; public DeviceProfile portraitProfile; @@ -99,11 +101,11 @@ public class InvariantDeviceProfile { this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns, p.numFolderRows, p.numFolderColumns, p.minAllAppsPredictionColumns, p.iconSize, p.landscapeIconSize, p.iconTextSize, p.numHotseatIcons, - p.defaultLayoutId); + p.defaultLayoutId, p.demoModeLayoutId); } InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc, - float is, float lis, float its, int hs, int dlId) { + float is, float lis, float its, int hs, int dlId, int dmlId) { name = n; minWidthDps = w; minHeightDps = h; @@ -117,6 +119,7 @@ public class InvariantDeviceProfile { iconTextSize = its; numHotseatIcons = hs; defaultLayoutId = dlId; + demoModeLayoutId = dmlId; } @TargetApi(23) @@ -144,6 +147,7 @@ public class InvariantDeviceProfile { numColumns = closestProfile.numColumns; numHotseatIcons = closestProfile.numHotseatIcons; defaultLayoutId = closestProfile.defaultLayoutId; + demoModeLayoutId = closestProfile.demoModeLayoutId; numFolderRows = closestProfile.numFolderRows; numFolderColumns = closestProfile.numFolderColumns; minAllAppsPredictionColumns = closestProfile.minAllAppsPredictionColumns; @@ -208,7 +212,8 @@ public class InvariantDeviceProfile { a.getFloat(R.styleable.InvariantDeviceProfile_landscapeIconSize, iconSize), a.getFloat(R.styleable.InvariantDeviceProfile_iconTextSize, 0), a.getInt(R.styleable.InvariantDeviceProfile_numHotseatIcons, numColumns), - a.getResourceId(R.styleable.InvariantDeviceProfile_defaultLayoutId, 0))); + a.getResourceId(R.styleable.InvariantDeviceProfile_defaultLayoutId, 0), + a.getResourceId(R.styleable.InvariantDeviceProfile_demoModeLayoutId, 0))); a.recycle(); } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index c22a04aa9..ba31926c2 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -16,6 +16,9 @@ package com.android.launcher3; +import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS; +import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS; + import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -53,8 +56,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Process; import android.os.StrictMode; -import android.os.SystemClock; -import android.os.Trace; import android.os.UserHandle; import android.support.annotation.Nullable; import android.text.Selection; @@ -73,7 +74,6 @@ import android.view.MotionEvent; import android.view.View; import android.view.View.OnLongClickListener; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -91,13 +91,13 @@ import com.android.launcher3.anim.AnimationLayerSet; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.LauncherAppsCompatVO; +import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.PinItemDragListener; -import com.android.launcher3.dynamicui.ExtractedColors; import com.android.launcher3.dynamicui.WallpaperColorInfo; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; @@ -118,7 +118,6 @@ 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.ComponentKeyMapper; import com.android.launcher3.util.ItemInfoMatcher; @@ -126,30 +125,30 @@ import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.PendingRequestArgs; +import com.android.launcher3.util.RunnableWithId; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.TestingUtils; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; +import com.android.launcher3.util.TraceHelper; +import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.ViewOnDrawExecutor; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.WidgetAddFlowHandler; import com.android.launcher3.widget.WidgetHostViewLoader; import com.android.launcher3.widget.WidgetsContainerView; +import com.android.launcher3.widget.custom.CustomWidgetParser; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; -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. */ @@ -161,9 +160,7 @@ public class Launcher extends BaseActivity public static final String TAG = "Launcher"; static final boolean LOGD = false; - static final boolean DEBUG_WIDGETS = false; static final boolean DEBUG_STRICT_MODE = false; - static final boolean DEBUG_RESUME_TIME = false; private static final int REQUEST_CREATE_SHORTCUT = 1; private static final int REQUEST_CREATE_APPWIDGET = 5; @@ -222,8 +219,6 @@ public class Launcher extends BaseActivity private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5; @Thunk static final int NEW_APPS_ANIMATION_DELAY = 500; - private final ExtractedColors mExtractedColors = new ExtractedColors(); - @Thunk Workspace mWorkspace; private View mLauncherView; @Thunk DragLayer mDragLayer; @@ -251,6 +246,10 @@ public class Launcher extends BaseActivity // Main container view and the model for the widget tray screen. @Thunk WidgetsContainerView mWidgetsView; + // We need to store the orientation Launcher was created with, due to a bug (b/64916689) + // that results in widgets being inflated in the wrong orientation. + private int mOrientation; + // 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. // Instead, just save the state that we need to restore Launcher to, and commit it in onResume. @@ -279,8 +278,6 @@ public class Launcher extends BaseActivity private PopupDataProvider mPopupDataProvider; - private View.OnTouchListener mHapticFeedbackTouchListener; - // Determines how long to wait after a rotation before restoring the screen orientation to // match the sensor state. private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500; @@ -296,28 +293,11 @@ public class Launcher extends BaseActivity // the press state and keep this reference to reset the press state when we return to launcher. private BubbleTextView mWaitingForResume; - protected static final HashMap<String, CustomAppWidget> sCustomAppWidgets = - new HashMap<>(); - - static { - if (TestingUtils.ENABLE_CUSTOM_WIDGET_TEST) { - TestingUtils.addDummyWidget(sCustomAppWidgets); - } - } - // Exiting spring loaded mode happens with a delay. This runnable object triggers the // state transition. If another state transition happened during this delay, // simply unregister this runnable. private Runnable mExitSpringLoadedModeRunnable; - @Thunk final Runnable mBuildLayersRunnable = new Runnable() { - public void run() { - if (mWorkspace != null) { - mWorkspace.buildPageHardwareLayers(); - } - } - }; - // Activity result which needs to be processed after workspace has loaded. private ActivityResultInfo mPendingActivityResult; /** @@ -358,9 +338,7 @@ public class Launcher extends BaseActivity .penaltyDeath() .build()); } - if (LauncherAppState.PROFILE_STARTUP) { - Trace.beginSection("Launcher-onCreate"); - } + TraceHelper.beginSection("Launcher-onCreate"); if (mLauncherCallbacks != null) { mLauncherCallbacks.preOnCreate(); @@ -371,6 +349,7 @@ public class Launcher extends BaseActivity overrideTheme(wallpaperColorInfo.isDark(), wallpaperColorInfo.supportsDarkText()); super.onCreate(savedInstanceState); + TraceHelper.partitionSection("Launcher-onCreate", "super call"); LauncherAppState app = LauncherAppState.getInstance(this); @@ -383,6 +362,7 @@ public class Launcher extends BaseActivity mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize); } + mOrientation = getResources().getConfiguration().orientation; mSharedPrefs = Utilities.getPrefs(this); mIsSafeModeEnabled = getPackageManager().isSafeMode(); mModel = app.setLauncher(this); @@ -411,7 +391,6 @@ public class Launcher extends BaseActivity setupViews(); mDeviceProfile.layout(this, false /* notifyListeners */); - loadExtractedColorsAndColorItems(); mPopupDataProvider = new PopupDataProvider(this); @@ -420,10 +399,6 @@ public class Launcher extends BaseActivity restoreState(savedInstanceState); - if (LauncherAppState.PROFILE_STARTUP) { - Trace.endSection(); - } - // We only load the page synchronously if the user rotates (or triggers a // configuration change) while launcher is in the foreground int currentScreen = PagedView.INVALID_RESTORE_PAGE; @@ -478,6 +453,8 @@ public class Launcher extends BaseActivity if (mLauncherCallbacks != null) { mLauncherCallbacks.onCreate(savedInstanceState); } + + TraceHelper.endSection("Launcher-onCreate"); } @Override @@ -499,27 +476,12 @@ public class Launcher extends BaseActivity } @Override - public void onExtractedColorsChanged() { - loadExtractedColorsAndColorItems(); - mExtractedColors.notifyChange(); - } - - @Override public void onAppWidgetHostReset() { if (mAppWidgetHost != null) { mAppWidgetHost.startListening(); } } - private void loadExtractedColorsAndColorItems() { - // TODO: do this in pre-N as well, once the extraction part is complete. - if (Utilities.ATLEAST_NOUGAT) { - mExtractedColors.load(this); - mHotseat.updateColor(mExtractedColors, !mPaused); - mWorkspace.getPageIndicator().updateColor(mExtractedColors); - } - } - private LauncherCallbacks mLauncherCallbacks; public void onPostCreate(Bundle savedInstanceState) { @@ -892,34 +854,23 @@ public class Launcher extends BaseActivity @Override protected void onResume() { - long startTime = 0; - if (DEBUG_RESUME_TIME) { - startTime = System.currentTimeMillis(); - Log.v(TAG, "Launcher.onResume()"); - } - + TraceHelper.beginSection("ON_RESUME"); if (mLauncherCallbacks != null) { mLauncherCallbacks.preOnResume(); } - super.onResume(); + TraceHelper.partitionSection("ON_RESUME", "superCall"); + getUserEventDispatcher().resetElapsedSessionMillis(); // Restore the previous launcher state if (mOnResumeState == State.WORKSPACE) { showWorkspace(false); } else if (mOnResumeState == State.APPS) { - boolean launchedFromApp = (mWaitingForResume != null); - // Don't update the predicted apps if the user is returning to launcher in the apps - // view after launching an app, as they may be depending on the UI to be static to - // switch to another app, otherwise, if it was - showAppsView(false /* animated */, !launchedFromApp /* updatePredictedApps */); + showAppsView(false /* animated */); } else if (mOnResumeState == State.WIDGETS) { showWidgetsView(false, false); } - if (mOnResumeState != State.APPS) { - tryAndUpdatePredictedApps(); - } mOnResumeState = State.NONE; mPaused = false; @@ -931,19 +882,10 @@ public class Launcher extends BaseActivity if (mBindOnResumeCallbacks.size() > 0) { // We might have postponed some bind calls until onResume (see waitUntilResume) -- // execute them here - long startTimeCallbacks = 0; - if (DEBUG_RESUME_TIME) { - startTimeCallbacks = System.currentTimeMillis(); - } - for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) { mBindOnResumeCallbacks.get(i).run(); } mBindOnResumeCallbacks.clear(); - if (DEBUG_RESUME_TIME) { - Log.d(TAG, "Time spent processing callbacks in onResume: " + - (System.currentTimeMillis() - startTimeCallbacks)); - } } if (mOnResumeCallbacks.size() > 0) { for (int i = 0; i < mOnResumeCallbacks.size(); i++) { @@ -959,20 +901,7 @@ public class Launcher extends BaseActivity mWaitingForResume.setStayPressed(false); } - // It is possible that widgets can receive updates while launcher is not in the foreground. - // Consequently, the widgets will be inflated in the orientation of the foreground activity - // (framework issue). On resuming, we ensure that any widgets are inflated for the current - // orientation. - if (!isWorkspaceLoading()) { - getWorkspace().reinflateWidgetsIfNecessary(); - } - - if (DEBUG_RESUME_TIME) { - Log.d(TAG, "Time spent in onResume: " + (System.currentTimeMillis() - startTime)); - } - updateInteraction(Workspace.State.NORMAL, mWorkspace.getState()); - mWorkspace.onResume(); // Process any items that were added while Launcher was away. InstallShortcutReceiver.disableAndFlushInstallQueue( @@ -988,6 +917,9 @@ public class Launcher extends BaseActivity mLauncherCallbacks.onResume(); } + clearTypedText(); + + TraceHelper.endSection("ON_RESUME"); } @Override @@ -1050,7 +982,7 @@ public class Launcher extends BaseActivity // On O and above we there is always some setting present settings (add icon to // home screen or icon badging). On earlier APIs we will have the allow rotation // setting, on devices with a locked orientation, - return Utilities.isAtLeastO() || !getResources().getBoolean(R.bool.allow_rotation); + return Utilities.ATLEAST_OREO || !getResources().getBoolean(R.bool.allow_rotation); } } @@ -1117,9 +1049,6 @@ public class Launcher extends BaseActivity // Close any open floating view AbstractFloatingView.closeAllOpenViews(this); - // Stop resizing any widgets - mWorkspace.exitWidgetResizeMode(); - // Show the overview mode if we are on the workspace if (mState == State.WORKSPACE && !mWorkspace.isInOverviewMode() && !mWorkspace.isSwitchingState()) { @@ -1234,7 +1163,6 @@ public class Launcher extends BaseActivity onClickWallpaperPicker(view); } }.attachTo(wallpaperButton); - wallpaperButton.setOnTouchListener(getHapticFeedbackTouchListener()); // Bind widget button actions mWidgetsButton = findViewById(R.id.widget_button); @@ -1244,7 +1172,6 @@ public class Launcher extends BaseActivity onClickAddWidgetButton(view); } }.attachTo(mWidgetsButton); - mWidgetsButton.setOnTouchListener(getHapticFeedbackTouchListener()); // Bind settings actions View settingsButton = findViewById(R.id.settings_button); @@ -1256,7 +1183,6 @@ public class Launcher extends BaseActivity onClickSettingsButton(view); } }.attachTo(settingsButton); - settingsButton.setOnTouchListener(getHapticFeedbackTouchListener()); } else { settingsButton.setVisibility(View.GONE); } @@ -1322,7 +1248,7 @@ public class Launcher extends BaseActivity CellLayout layout = getCellLayout(container, screenId); ShortcutInfo info = null; - if (Utilities.isAtLeastO()) { + if (Utilities.ATLEAST_OREO) { info = LauncherAppsCompatVO.createShortcutInfoFromPinItemRequest( this, LauncherAppsCompatVO.getPinItemRequest(data), 0); } @@ -1408,17 +1334,13 @@ public class Launcher extends BaseActivity appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(appWidgetId); } - if (appWidgetInfo.isCustomWidget) { - appWidgetId = LauncherAppWidgetInfo.CUSTOM_WIDGET_ID; - } - LauncherAppWidgetInfo launcherInfo; launcherInfo = new LauncherAppWidgetInfo(appWidgetId, appWidgetInfo.provider); launcherInfo.spanX = itemInfo.spanX; launcherInfo.spanY = itemInfo.spanY; launcherInfo.minSpanX = itemInfo.minSpanX; launcherInfo.minSpanY = itemInfo.minSpanY; - launcherInfo.user = appWidgetInfo.getUser(); + launcherInfo.user = appWidgetInfo.getProfile(); getModelWriter().addItemToDatabase(launcherInfo, itemInfo.container, itemInfo.screenId, itemInfo.cellX, itemInfo.cellY); @@ -1444,8 +1366,6 @@ public class Launcher extends BaseActivity public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (Intent.ACTION_SCREEN_OFF.equals(action)) { - mDragLayer.clearResizeFrame(); - // Reset AllApps to its initial state only if we are not in the middle of // processing a multi-step drop if (mAppsView != null && mWidgetsView != null && mPendingRequestArgs == null) { @@ -1500,44 +1420,6 @@ public class Launcher extends BaseActivity } } - public void onWindowVisibilityChanged(int visibility) { - // The following code used to be in onResume, but it turns out onResume is called when - // you're in All Apps and click home to go to the workspace. onWindowVisibilityChanged - // is a more appropriate event to handle - if (visibility == View.VISIBLE) { - if (!mWorkspaceLoading) { - final ViewTreeObserver observer = mWorkspace.getViewTreeObserver(); - // We want to let Launcher draw itself at least once before we force it to build - // layers on all the workspace pages, so that transitioning to Launcher from other - // apps is nice and speedy. - observer.addOnDrawListener(new ViewTreeObserver.OnDrawListener() { - private boolean mStarted = false; - public void onDraw() { - if (mStarted) return; - mStarted = true; - // We delay the layer building a bit in order to give - // other message processing a time to run. In particular - // this avoids a delay in hiding the IME if it was - // currently shown, because doing that may involve - // some communication back with the app. - mWorkspace.postDelayed(mBuildLayersRunnable, 500); - final ViewTreeObserver.OnDrawListener listener = this; - mWorkspace.post(new Runnable() { - public void run() { - if (mWorkspace != null && - mWorkspace.getViewTreeObserver() != null) { - mWorkspace.getViewTreeObserver(). - removeOnDrawListener(listener); - } - } - }); - } - }); - } - clearTypedText(); - } - } - public DragLayer getDragLayer() { return mDragLayer; } @@ -1582,12 +1464,11 @@ public class Launcher extends BaseActivity return mSharedPrefs; } + public int getOrientation() { return mOrientation; } + @Override protected void onNewIntent(Intent intent) { - long startTime = 0; - if (DEBUG_RESUME_TIME) { - startTime = System.currentTimeMillis(); - } + TraceHelper.beginSection("NEW_INTENT"); super.onNewIntent(intent); boolean alreadyOnHome = mHasFocus && ((intent.getFlags() & @@ -1608,17 +1489,9 @@ public class Launcher extends BaseActivity // Note: There should be at most one log per method call. This is enforced implicitly // by using if-else statements. UserEventDispatcher ued = getUserEventDispatcher(); - - // TODO: Log this case. - mWorkspace.exitWidgetResizeMode(); - AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(this); - if (topOpenView instanceof PopupContainerWithArrow) { - ued.logActionCommand(Action.Command.HOME_INTENT, - topOpenView.getExtendedTouchView(), ContainerType.DEEPSHORTCUTS); - } else if (topOpenView instanceof Folder) { - ued.logActionCommand(Action.Command.HOME_INTENT, - ((Folder) topOpenView).getFolderIcon(), ContainerType.FOLDER); + if (topOpenView != null) { + topOpenView.logActionCommand(Action.Command.HOME_INTENT); } else if (alreadyOnHome) { ued.logActionCommand(Action.Command.HOME_INTENT, mWorkspace.getState().containerType, mWorkspace.getCurrentPage()); @@ -1638,9 +1511,7 @@ public class Launcher extends BaseActivity final View v = getWindow().peekDecorView(); if (v != null && v.getWindowToken() != null) { - InputMethodManager imm = (InputMethodManager) getSystemService( - INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(v.getWindowToken(), 0); + UiThreadHelper.hideKeyboardAsync(this, v.getWindowToken()); } // Reset the apps view @@ -1684,9 +1555,7 @@ public class Launcher extends BaseActivity } } - if (DEBUG_RESUME_TIME) { - Log.d(TAG, "Time spent in onNewIntent: " + (System.currentTimeMillis() - startTime)); - } + TraceHelper.endSection("NEW_INTENT"); } @Override @@ -1727,7 +1596,6 @@ public class Launcher extends BaseActivity super.onDestroy(); unregisterReceiver(mReceiver); - mWorkspace.removeCallbacks(mBuildLayersRunnable); mWorkspace.removeFolderListeners(); // Stop callbacks from LauncherModel @@ -1968,7 +1836,7 @@ public class Launcher extends BaseActivity */ private void addAppWidgetFromDrop(PendingAddWidgetInfo info) { AppWidgetHostView hostView = info.boundWidget; - int appWidgetId; + final int appWidgetId; WidgetAddFlowHandler addFlowHandler = info.getHandler(); if (hostView != null) { // In the case where we've prebound the widget, we remove it from the DragLayer @@ -1985,7 +1853,13 @@ public class Launcher extends BaseActivity } else { // In this case, we either need to start an activity to get permission to bind // the widget, or we need to start an activity to configure the widget, or both. - appWidgetId = getAppWidgetHost().allocateAppWidgetId(); + if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && + info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) { + appWidgetId = CustomWidgetParser.getWidgetIdForCustomProvider( + this, info.componentName); + } else { + appWidgetId = getAppWidgetHost().allocateAppWidgetId(); + } Bundle options = info.bindOptions; boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( @@ -2094,18 +1968,7 @@ public class Launcher extends BaseActivity UserEventDispatcher ued = getUserEventDispatcher(); AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this); if (topView != null) { - if (topView.getActiveTextView() != null) { - topView.getActiveTextView().dispatchBackKey(); - } else { - if (topView instanceof PopupContainerWithArrow) { - ued.logActionCommand(Action.Command.BACK, - topView.getExtendedTouchView(), ContainerType.DEEPSHORTCUTS); - } else if (topView instanceof Folder) { - ued.logActionCommand(Action.Command.BACK, - ((Folder) topView).getFolderIcon(), ContainerType.FOLDER); - } - topView.close(true); - } + topView.onBackPressed(); } else if (isAppsViewVisible()) { ued.logActionCommand(Action.Command.BACK, ContainerType.ALLAPPS); showWorkspace(true); @@ -2116,9 +1979,6 @@ public class Launcher extends BaseActivity ued.logActionCommand(Action.Command.BACK, ContainerType.OVERVIEW); showWorkspace(true); } else { - // TODO: Log this case. - mWorkspace.exitWidgetResizeMode(); - // Back button is a no-op here, but give at least some feedback for the button press mWorkspace.showOutlinesTemporarily(); } @@ -2232,7 +2092,7 @@ public class Launcher extends BaseActivity if (!isAppsViewVisible()) { getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, ControlType.ALL_APPS_BUTTON); - showAppsView(true /* animated */, true /* updatePredictedApps */); + showAppsView(true /* animated */); } else { showWorkspace(true); } @@ -2427,22 +2287,6 @@ public class Launcher extends BaseActivity startActivity(intent, getActivityLaunchOptions(v)); } - public View.OnTouchListener getHapticFeedbackTouchListener() { - if (mHapticFeedbackTouchListener == null) { - mHapticFeedbackTouchListener = new View.OnTouchListener() { - @SuppressLint("ClickableViewAccessibility") - @Override - public boolean onTouch(View v, MotionEvent event) { - if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) { - v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); - } - return false; - } - }; - } - return mHapticFeedbackTouchListener; - } - @Override public void onAccessibilityStateChanged(boolean enabled) { mDragLayer.onAccessibilityStateChanged(enabled); @@ -2813,11 +2657,8 @@ public class Launcher extends BaseActivity /** * Shows the apps view. */ - public void showAppsView(boolean animated, boolean updatePredictedApps) { + public void showAppsView(boolean animated) { markAppsViewShown(); - if (updatePredictedApps) { - tryAndUpdatePredictedApps(); - } showAppsOrWidgets(State.APPS, animated); } @@ -2937,7 +2778,7 @@ public class Launcher extends BaseActivity public void exitSpringLoadedDragMode() { if (mState == State.APPS_SPRING_LOADED) { - showAppsView(true /* animated */, false /* updatePredictedApps */); + showAppsView(true /* animated */); } else if (mState == State.WIDGETS_SPRING_LOADED) { showWidgetsView(true, false); } else if (mState == State.WORKSPACE_SPRING_LOADED) { @@ -2945,19 +2786,6 @@ public class Launcher extends BaseActivity } } - /** - * Updates the set of predicted apps if it hasn't been updated since the last time Launcher was - * resumed. - */ - public void tryAndUpdatePredictedApps() { - if (mLauncherCallbacks != null) { - List<ComponentKeyMapper<AppInfo>> apps = mLauncherCallbacks.getPredictedApps(); - if (apps != null) { - mAppsView.setPredictedApps(apps); - } - } - } - @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { final boolean result = super.dispatchPopulateAccessibilityEvent(event); @@ -3063,10 +2891,7 @@ public class Launcher extends BaseActivity * Implementation of the method from LauncherModel.Callbacks. */ public void startBinding() { - if (LauncherAppState.PROFILE_STARTUP) { - Trace.beginSection("Starting page bind"); - } - + TraceHelper.beginSection("startBinding"); AbstractFloatingView.closeAllOpenViews(this); setWorkspaceLoading(true); @@ -3078,9 +2903,7 @@ public class Launcher extends BaseActivity if (mHotseat != null) { mHotseat.resetLayout(); } - if (LauncherAppState.PROFILE_STARTUP) { - Trace.endSection(); - } + TraceHelper.endSection("startBinding"); } @Override @@ -3192,7 +3015,8 @@ public class Launcher extends BaseActivity (FolderInfo) item); break; } - case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: { + case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: + case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: { view = inflateAppWidget((LauncherAppWidgetInfo) item); if (view == null) { continue; @@ -3283,10 +3107,7 @@ public class Launcher extends BaseActivity return view; } - final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0; - if (DEBUG_WIDGETS) { - Log.d(TAG, "bindAppWidget: " + item); - } + TraceHelper.beginSection("BIND_WIDGET"); final LauncherAppWidgetProviderInfo appWidgetInfo; @@ -3304,11 +3125,9 @@ public class Launcher extends BaseActivity if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) { if (appWidgetInfo == null) { - if (DEBUG_WIDGETS) { - Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId - + " belongs to component " + item.providerName - + ", as the provider is null"); - } + Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId + + " belongs to component " + item.providerName + + ", as the provider is null"); getModelWriter().deleteItemFromDatabase(item); return null; } @@ -3369,11 +3188,6 @@ public class Launcher extends BaseActivity final AppWidgetHostView view; if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) { - if (DEBUG_WIDGETS) { - Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " - + appWidgetInfo.provider); - } - // Verify that we own the widget if (appWidgetInfo == null) { FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId); @@ -3389,10 +3203,7 @@ public class Launcher extends BaseActivity } prepareAppWidget(view, item); - if (DEBUG_WIDGETS) { - Log.d(TAG, "bound widget id="+item.appWidgetId+" in " - + (SystemClock.uptimeMillis()-start) + "ms"); - } + TraceHelper.endSection("BIND_WIDGET", "id=" + item.appWidgetId); return view; } @@ -3414,7 +3225,10 @@ public class Launcher extends BaseActivity info.pendingItemInfo = null; } - mWorkspace.reinflateWidgetsIfNecessary(); + if (((PendingAppWidgetHostView) view).isReinflateIfNeeded()) { + view.reinflate(); + } + getModelWriter().updateItemInDatabase(info); return info; } @@ -3478,9 +3292,7 @@ public class Launcher extends BaseActivity if (waitUntilResume(r)) { return; } - if (LauncherAppState.PROFILE_STARTUP) { - Trace.beginSection("Page bind completed"); - } + TraceHelper.beginSection("finishBindingItems"); mWorkspace.restoreInstanceStateForRemainingPages(); setWorkspaceLoading(false); @@ -3499,9 +3311,7 @@ public class Launcher extends BaseActivity if (mLauncherCallbacks != null) { mLauncherCallbacks.finishBindingItems(false); } - if (LauncherAppState.PROFILE_STARTUP) { - Trace.endSection(); - } + TraceHelper.endSection("finishBindingItems"); } private boolean canRunNewAppsAnimation() { @@ -3693,7 +3503,6 @@ public class Launcher extends BaseActivity // Update AllApps if (mAppsView != null) { mAppsView.removeApps(appInfos); - tryAndUpdatePredictedApps(); } } @@ -3771,7 +3580,8 @@ public class Launcher extends BaseActivity } private boolean shouldShowDiscoveryBounce() { - return mState == State.WORKSPACE && !mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false); + UserManagerCompat um = UserManagerCompat.getInstance(this); + return mState == State.WORKSPACE && !mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false) && !um.isDemoUser(); } /** @@ -3856,7 +3666,7 @@ public class Launcher extends BaseActivity switch (keyCode) { case KeyEvent.KEYCODE_A: if (mState == State.WORKSPACE) { - showAppsView(true, true); + showAppsView(true); return true; } break; @@ -3882,14 +3692,6 @@ public class Launcher extends BaseActivity return super.onKeyShortcut(keyCode, event); } - public static CustomAppWidget getCustomAppWidget(String name) { - return sCustomAppWidgets.get(name); - } - - public static HashMap<String, CustomAppWidget> getCustomAppWidgets() { - return sCustomAppWidgets; - } - public static Launcher getLauncher(Context context) { if (context instanceof Launcher) { return (Launcher) context; diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 1ffe41bc6..dfb30fd35 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -28,7 +28,6 @@ import com.android.launcher3.compat.LauncherAppsCompat; 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; @@ -42,8 +41,6 @@ import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING; public class LauncherAppState { - public static final boolean PROFILE_STARTUP = FeatureFlags.IS_DOGFOOD_BUILD; - // We do not need any synchronization for this variable as its only written on UI thread. private static LauncherAppState INSTANCE; @@ -111,18 +108,11 @@ public class LauncherAppState { filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED); - // For extracting colors from the wallpaper - if (Utilities.ATLEAST_NOUGAT) { - // TODO: add a broadcast entry to the manifest for pre-N. - filter.addAction(Intent.ACTION_WALLPAPER_CHANGED); - } mContext.registerReceiver(mModel, filter); UserManagerCompat.getInstance(mContext).enableAndResetCache(); new ConfigMonitor(mContext).register(); - ExtractionUtils.startColorExtractionServiceIfNecessary(mContext); - if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) { mNotificationBadgingObserver = null; } else { diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java index 5573c5c15..70440fa30 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/LauncherAppWidgetHost.java @@ -116,13 +116,12 @@ public class LauncherAppWidgetHost extends AppWidgetHost { public AppWidgetHostView createView(Context context, int appWidgetId, LauncherAppWidgetProviderInfo appWidget) { - if (appWidget.isCustomWidget) { + if (appWidget.isCustomWidget()) { LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context); LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(appWidget.initialLayout, lahv); lahv.setAppWidget(0, appWidget); - lahv.updateLastInflationOrientation(); return lahv; } else { try { diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java index c7b778252..6f953e5f0 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java @@ -19,6 +19,7 @@ package com.android.launcher3; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; +import android.content.res.Configuration; import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; @@ -58,10 +59,14 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView private final CheckLongPressHelper mLongPressHelper; private final StylusEventHelper mStylusEventHelper; - private final Context mContext; + private final Launcher mLauncher; + + private static final int DONT_REINFLATE = 0; + private static final int REINFLATE_ON_RESUME = 1; + private static final int REINFLATE_ON_CONFIG_CHANGE = 2; @ViewDebug.ExportedProperty(category = "launcher") - private int mPreviousOrientation; + private int mReinflateStatus; private float mSlop; @@ -85,14 +90,14 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView public LauncherAppWidgetHostView(Context context) { super(context); - mContext = context; + mLauncher = Launcher.getLauncher(context); mLongPressHelper = new CheckLongPressHelper(this, this); mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this); mInflater = LayoutInflater.from(context); - setAccessibilityDelegate(Launcher.getLauncher(context).getAccessibilityDelegate()); + setAccessibilityDelegate(mLauncher.getAccessibilityDelegate()); setBackgroundResource(R.drawable.widget_internal_focus_bg); - if (Utilities.isAtLeastO()) { + if (Utilities.ATLEAST_OREO) { setExecutor(Utilities.THREAD_POOL_EXECUTOR); } } @@ -112,18 +117,28 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView return mInflater.inflate(R.layout.appwidget_error, this, false); } - public void updateLastInflationOrientation() { - mPreviousOrientation = mContext.getResources().getConfiguration().orientation; - } - @Override public void updateAppWidget(RemoteViews remoteViews) { - // Store the orientation in which the widget was inflated - updateLastInflationOrientation(); super.updateAppWidget(remoteViews); // The provider info or the views might have changed. checkIfAutoAdvance(); + + // It is possible that widgets can receive updates while launcher is not in the foreground. + // Consequently, the widgets will be inflated for the orientation of the foreground activity + // (framework issue). On resuming, we ensure that any widgets are inflated for the current + // orientation. + if (mReinflateStatus == DONT_REINFLATE && !isSameOrientation()) { + mReinflateStatus = REINFLATE_ON_RESUME; + if (!mLauncher.waitUntilResume(new ReInflateRunnable())) { + mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE; + } + } + } + + private boolean isSameOrientation() { + return mLauncher.getResources().getConfiguration().orientation == + mLauncher.getOrientation(); } private boolean checkScrollableRecursively(ViewGroup viewGroup) { @@ -142,15 +157,6 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView return false; } - public boolean isReinflateRequired() { - // Re-inflate is required if the orientation has changed since last inflated. - int orientation = mContext.getResources().getConfiguration().orientation; - if (mPreviousOrientation != orientation) { - return true; - } - return false; - } - public boolean onInterceptTouchEvent(MotionEvent ev) { // Just in case the previous long press hasn't been cleared, we make sure to start fresh // on touch down. @@ -474,4 +480,45 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView public PointF getTranslationForCentering() { return mTranslationForCentering; } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + if (mReinflateStatus == REINFLATE_ON_CONFIG_CHANGE) { + // We are finally in the same orientation + reinflateIfNecessary(); + } + } + + private void reinflateIfNecessary() { + if (!isSameOrientation()) { + // We cannot reinflate yet, wait until next config change + mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE; + return; + } + + mReinflateStatus = DONT_REINFLATE; + if (isAttachedToWindow()) { + LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); + reinflate(); + } + } + + public void reinflate() { + LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); + // Remove and rebind the current widget (which was inflated in the wrong + // orientation), but don't delete it from the database + mLauncher.removeItem(this, info, false /* deleteFromDb */); + mLauncher.bindAppWidget(info); + } + + private class ReInflateRunnable implements Runnable { + @Override + public void run() { + if (mReinflateStatus == REINFLATE_ON_RESUME) { + reinflateIfNecessary(); + } + } + } } diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java index 6f23e56b3..051846c87 100644 --- a/src/com/android/launcher3/LauncherAppWidgetInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java @@ -71,7 +71,7 @@ public class LauncherAppWidgetInfo extends ItemInfo { /** * Indicates that this is a locally defined widget and hence has no system allocated id. */ - static final int CUSTOM_WIDGET_ID = -100; + public static final int CUSTOM_WIDGET_ID = -100; /** * Identifier for this widget when talking with @@ -104,15 +104,15 @@ public class LauncherAppWidgetInfo extends ItemInfo { private boolean mHasNotifiedInitialWidgetSizeChanged; public LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) { - if (appWidgetId == CUSTOM_WIDGET_ID) { + this.appWidgetId = appWidgetId; + this.providerName = providerName; + + if (isCustomWidget()) { itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; } else { itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; } - this.appWidgetId = appWidgetId; - this.providerName = providerName; - // Since the widget isn't instantiated yet, we don't know these values. Set them to -1 // to indicate that they should be calculated based on the layout and minWidth/minHeight spanX = -1; @@ -128,7 +128,7 @@ public class LauncherAppWidgetInfo extends ItemInfo { } public boolean isCustomWidget() { - return appWidgetId == CUSTOM_WIDGET_ID; + return appWidgetId <= CUSTOM_WIDGET_ID; } @Override diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java index 6cb703b43..c7139925c 100644 --- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java @@ -2,15 +2,11 @@ package com.android.launcher3; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; -import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.Parcel; -import android.os.Process; -import android.os.UserHandle; /** * This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords @@ -20,7 +16,7 @@ import android.os.UserHandle; */ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { - public boolean isCustomWidget = false; + public static final String CLS_CUSTOM_WIDGET_PREFIX = "#custom-widget-"; public int spanX; public int spanY; @@ -48,20 +44,10 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { return launcherInfo; } - private LauncherAppWidgetProviderInfo(Parcel in) { - super(in); - } - - public LauncherAppWidgetProviderInfo(Context context, CustomAppWidget widget) { - isCustomWidget = true; + protected LauncherAppWidgetProviderInfo() {} - provider = new ComponentName(context, widget.getClass().getName()); - icon = widget.getIcon(); - label = widget.getLabel(); - previewImage = widget.getPreviewImage(); - initialLayout = widget.getWidgetLayout(); - resizeMode = widget.getResizeMode(); - initSpans(context); + protected LauncherAppWidgetProviderInfo(Parcel in) { + super(in); } public void initSpans(Context context) { @@ -97,34 +83,15 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { } public String getLabel(PackageManager packageManager) { - if (isCustomWidget) { - return Utilities.trim(label); - } return super.loadLabel(packageManager); } - public Drawable getIcon(Context context, IconCache cache) { - if (isCustomWidget) { - return cache.getFullResIcon(provider.getPackageName(), icon); - } - return super.loadIcon(context, LauncherAppState.getIDP(context).fillResIconDpi); - } - - public String toString(PackageManager pm) { - if (isCustomWidget) { - return "WidgetProviderInfo(" + provider + ")"; - } - return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s", - provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm)); - } - - public Point getMinSpans(InvariantDeviceProfile idp, Context context) { - return new Point( - (resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpanX : -1, - (resizeMode & RESIZE_VERTICAL) != 0 ? minSpanY : -1); + public Point getMinSpans() { + return new Point((resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpanX : -1, + (resizeMode & RESIZE_VERTICAL) != 0 ? minSpanY : -1); } - public UserHandle getUser() { - return isCustomWidget ? Process.myUserHandle() : getProfile(); + public boolean isCustomWidget() { + return provider.getClassName().startsWith(CLS_CUSTOM_WIDGET_PREFIX); } } diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java index d1e2b621a..2c9a23fa9 100644 --- a/src/com/android/launcher3/LauncherCallbacks.java +++ b/src/com/android/launcher3/LauncherCallbacks.java @@ -19,14 +19,10 @@ package com.android.launcher3; import android.content.Intent; import android.os.Bundle; import android.view.Menu; -import android.view.View; - -import com.android.launcher3.util.ComponentKeyMapper; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.List; /** * LauncherCallbacks is an interface used to extend the Launcher activity. It includes many hooks @@ -87,5 +83,4 @@ public interface LauncherCallbacks { */ boolean shouldMoveToDefaultScreenOnHomeIntent(); boolean hasSettings(); - List<ComponentKeyMapper<AppInfo>> getPredictedApps(); } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index a906b00f1..74a5bac99 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -37,7 +37,6 @@ import android.util.Pair; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserManagerCompat; -import com.android.launcher3.dynamicui.ExtractionUtils; import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.model.AddWorkspaceItemsTask; import com.android.launcher3.model.BgDataModel; @@ -406,8 +405,6 @@ public class LauncherModel extends BroadcastReceiver enqueueModelUpdateTask(new UserLockStateChangedTask(user)); } } - } else if (Intent.ACTION_WALLPAPER_CHANGED.equals(action)) { - ExtractionUtils.startColorExtractionServiceIfNecessary(context); } } diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index dc83f36ad..25a698b15 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -55,7 +55,6 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.WorkspaceScreens; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.dynamicui.ExtractionUtils; import com.android.launcher3.graphics.IconShapeOverride; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.DbDowngradeHelper; @@ -149,9 +148,6 @@ public class LauncherProvider extends ContentProvider { */ protected synchronized void createDbIfNotExists() { if (mOpenHelper == null) { - if (LauncherAppState.PROFILE_STARTUP) { - Trace.beginSection("Opening workspace DB"); - } mOpenHelper = new DatabaseHelper(getContext(), mListenerHandler); if (RestoreDbTask.isPending(getContext())) { @@ -162,10 +158,6 @@ public class LauncherProvider extends ContentProvider { // executed again. RestoreDbTask.setPending(getContext(), false); } - - if (LauncherAppState.PROFILE_STARTUP) { - Trace.endSection(); - } } } @@ -372,19 +364,6 @@ public class LauncherProvider extends ContentProvider { createDbIfNotExists(); switch (method) { - case LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID: { - String extractedColors = extras.getString( - LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS); - int wallpaperId = extras.getInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID); - Utilities.getPrefs(getContext()).edit() - .putString(ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, extractedColors) - .putInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, wallpaperId) - .apply(); - mListenerHandler.sendEmptyMessage(ChangeListenerWrapper.MSG_EXTRACTED_COLORS_CHANGED); - Bundle result = new Bundle(); - result.putString(LauncherSettings.Settings.EXTRA_VALUE, extractedColors); - return result; - } case LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG: { clearFlagEmptyDbCreated(); return null; @@ -552,7 +531,14 @@ public class LauncherProvider extends ContentProvider { } private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) { - int defaultLayout = LauncherAppState.getIDP(getContext()).defaultLayoutId; + InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext()); + int defaultLayout = idp.defaultLayoutId; + + UserManagerCompat um = UserManagerCompat.getInstance(getContext()); + if (um.isDemoUser() && idp.demoModeLayoutId != 0) { + defaultLayout = idp.demoModeLayoutId; + } + return new DefaultLayoutParser(getContext(), widgetHost, mOpenHelper, getContext().getResources(), defaultLayout); } @@ -1153,8 +1139,7 @@ public class LauncherProvider extends ContentProvider { private static class ChangeListenerWrapper implements Handler.Callback { private static final int MSG_LAUNCHER_PROVIDER_CHANGED = 1; - private static final int MSG_EXTRACTED_COLORS_CHANGED = 2; - private static final int MSG_APP_WIDGET_HOST_RESET = 3; + private static final int MSG_APP_WIDGET_HOST_RESET = 2; private LauncherProviderChangeListener mListener; @@ -1165,9 +1150,6 @@ public class LauncherProvider extends ContentProvider { case MSG_LAUNCHER_PROVIDER_CHANGED: mListener.onLauncherProviderChanged(); break; - case MSG_EXTRACTED_COLORS_CHANGED: - mListener.onExtractedColorsChanged(); - break; case MSG_APP_WIDGET_HOST_RESET: mListener.onAppWidgetHostReset(); break; diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java index 704481232..024308863 100644 --- a/src/com/android/launcher3/LauncherProviderChangeListener.java +++ b/src/com/android/launcher3/LauncherProviderChangeListener.java @@ -9,7 +9,5 @@ public interface LauncherProviderChangeListener { void onLauncherProviderChanged(); - void onExtractedColorsChanged(); - void onAppWidgetHostReset(); } diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 87f62eb01..3b337ef18 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -304,11 +304,6 @@ public class LauncherSettings { public static final String METHOD_LOAD_DEFAULT_FAVORITES = "load_default_favorites"; - public static final String METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID = - "set_extracted_colors_and_wallpaper_id_setting"; - public static final String EXTRA_EXTRACTED_COLORS = "extra_extractedColors"; - public static final String EXTRA_WALLPAPER_ID = "extra_wallpaperId"; - public static final String METHOD_REMOVE_GHOST_WIDGETS = "remove_ghost_widgets"; public static final String EXTRA_VALUE = "value"; diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java index de424aba1..b86d41318 100644 --- a/src/com/android/launcher3/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/PendingAppWidgetHostView.java @@ -110,9 +110,7 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView mClickListener = l; } - @Override - public boolean isReinflateRequired() { - // Re inflate is required any time the widget restore status changes + public boolean isReinflateIfNeeded() { return mStartState != mInfo.restoreStatus; } diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java index 8caba75cd..edb7ff533 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -59,7 +59,7 @@ public class SessionCommitReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (!isEnabled(context) || !Utilities.isAtLeastO()) { + if (!isEnabled(context) || !Utilities.ATLEAST_OREO) { // User has decided to not add icons on homescreen. return; } @@ -92,7 +92,7 @@ public class SessionCommitReceiver extends BroadcastReceiver { } public static void applyDefaultUserPrefs(final Context context) { - if (!Utilities.isAtLeastO()) { + if (!Utilities.ATLEAST_OREO) { return; } SharedPreferences prefs = Utilities.getPrefs(context); diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java index 5bdc1f5bd..d40ac8f97 100644 --- a/src/com/android/launcher3/SettingsActivity.java +++ b/src/com/android/launcher3/SettingsActivity.java @@ -94,7 +94,7 @@ public class SettingsActivity extends Activity { ButtonPreference iconBadgingPref = (ButtonPreference) findPreference(ICON_BADGING_PREFERENCE_KEY); - if (!Utilities.isAtLeastO()) { + if (!Utilities.ATLEAST_OREO) { getPreferenceScreen().removePreference( findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY)); getPreferenceScreen().removePreference(iconBadgingPref); diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java index 84d6a9b34..3f7de0604 100644 --- a/src/com/android/launcher3/UninstallDropTarget.java +++ b/src/com/android/launcher3/UninstallDropTarget.java @@ -21,6 +21,7 @@ import java.net.URISyntaxException; public class UninstallDropTarget extends ButtonDropTarget { private static final String TAG = "UninstallDropTarget"; + private static Boolean sUninstallDisabled; public UninstallDropTarget(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -43,18 +44,27 @@ public class UninstallDropTarget extends ButtonDropTarget { } @Override - protected boolean supportsDrop(DragSource source, ItemInfo info) { + protected boolean supportsDrop(ItemInfo info) { return supportsDrop(getContext(), 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) - || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) { + if (sUninstallDisabled == null) { + UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + Bundle restrictions = userManager.getUserRestrictions(); + sUninstallDisabled = restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) + || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false); + } + if (sUninstallDisabled) { return false; } + if (info instanceof AppInfo) { + AppInfo appInfo = (AppInfo) info; + if (appInfo.isSystemApp != AppInfo.FLAG_SYSTEM_UNKNOWN) { + return (appInfo.isSystemApp & AppInfo.FLAG_SYSTEM_NO) != 0; + } + } return getUninstallTarget(context, info) != null; } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 3aa2db000..71677782d 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -83,15 +83,17 @@ public final class Utilities { private static final Matrix sMatrix = new Matrix(); private static final Matrix sInverseMatrix = new Matrix(); - public static boolean isAtLeastO() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; - } + public static final boolean ATLEAST_OREO_MR1 = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1; + + public static final boolean ATLEAST_OREO = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; public static final boolean ATLEAST_NOUGAT_MR1 = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1; + Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1; public static final boolean ATLEAST_NOUGAT = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; + Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; public static final boolean ATLEAST_MARSHMALLOW = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; @@ -307,6 +309,9 @@ public final class Utilities { float highScore = -1; int bestHue = -1; + int[] pixels = new int[samples]; + int pixelCount = 0; + for (int y = 0; y < height; y += sampleStride) { for (int x = 0; x < width; x += sampleStride) { int argb = bitmap.getPixel(x, y); @@ -324,6 +329,9 @@ public final class Utilities { // Defensively avoid array bounds violations. continue; } + if (pixelCount < samples) { + pixels[pixelCount++] = rgb; + } float score = hsv[1] * hsv[2]; hueScoreHistogram[hue] += score; if (hueScoreHistogram[hue] > highScore) { @@ -333,31 +341,29 @@ public final class Utilities { } } - SparseArray<Float> rgbScores = new SparseArray<Float>(); + SparseArray<Float> rgbScores = new SparseArray<>(); int bestColor = 0xff000000; highScore = -1; // Go back over the RGB colors that match the winning hue, // creating a histogram of weighted s*v scores, for up to 100*100 [s,v] buckets. // The highest-scoring RGB color wins. - for (int y = 0; y < height; y += sampleStride) { - for (int x = 0; x < width; x += sampleStride) { - int rgb = bitmap.getPixel(x, y) | 0xff000000; - Color.colorToHSV(rgb, hsv); - int hue = (int) hsv[0]; - if (hue == bestHue) { - float s = hsv[1]; - float v = hsv[2]; - int bucket = (int) (s * 100) + (int) (v * 10000); - // Score by cumulative saturation * value. - float score = s * v; - Float oldTotal = rgbScores.get(bucket); - float newTotal = oldTotal == null ? score : oldTotal + score; - rgbScores.put(bucket, newTotal); - if (newTotal > highScore) { - highScore = newTotal; - // All the colors in the winning bucket are very similar. Last in wins. - bestColor = rgb; - } + for (int i = 0; i < pixelCount; i++) { + int rgb = pixels[i]; + Color.colorToHSV(rgb, hsv); + int hue = (int) hsv[0]; + if (hue == bestHue) { + float s = hsv[1]; + float v = hsv[2]; + int bucket = (int) (s * 100) + (int) (v * 10000); + // Score by cumulative saturation * value. + float score = s * v; + Float oldTotal = rgbScores.get(bucket); + float newTotal = oldTotal == null ? score : oldTotal + score; + rgbScores.put(bucket, newTotal); + if (newTotal > highScore) { + highScore = newTotal; + // All the colors in the winning bucket are very similar. Last in wins. + bestColor = rgb; } } } diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index a65ea9b10..f150c89c1 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -22,7 +22,6 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import android.os.Build; import android.os.CancellationSignal; import android.os.Handler; import android.os.UserHandle; @@ -412,7 +411,8 @@ public class WidgetPreviewLoader { // Draw icon in the center. try { - Drawable icon = info.getIcon(launcher, mIconCache); + Drawable icon = + mIconCache.getFullResIcon(info.provider.getPackageName(), info.icon); if (icon != null) { int appIconSize = launcher.getDeviceProfile().iconSizePx; int iconSize = (int) Math.min(appIconSize * scale, diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 59437f608..95f748400 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -228,7 +228,6 @@ public class Workspace extends PagedView private State mState = State.NORMAL; private boolean mIsSwitchingState = false; - boolean mAnimatingViewIntoPlace = false; boolean mChildrenLayersEnabled = true; private boolean mStripScreensOnPageStopMoving = false; @@ -252,8 +251,6 @@ public class Workspace extends PagedView private boolean mAddToExistingFolderOnDrop = false; private float mMaxDistanceForFolderCreation; - private final Canvas mCanvas = new Canvas(); - // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget) private float mXDown; private float mYDown; @@ -351,12 +348,9 @@ public class Workspace extends PagedView /** * Estimates the size of an item using spans: hSpan, vSpan. * - * @param springLoaded True if we are in spring loaded mode. - * @param unscaledSize True if caller wants to return the unscaled size * @return MAX_VALUE for each dimension if unsuccessful. */ - public int[] estimateItemSize(ItemInfo itemInfo, boolean springLoaded, boolean unscaledSize) { - float shrinkFactor = mLauncher.getDeviceProfile().workspaceSpringLoadShrinkFactor; + public int[] estimateItemSize(ItemInfo itemInfo) { int[] size = new int[2]; if (getChildCount() > 0) { // Use the first page to estimate the child position @@ -373,15 +367,10 @@ public class Workspace extends PagedView size[0] = r.width(); size[1] = r.height(); - if (isWidget && unscaledSize) { + if (isWidget) { size[0] /= scale; size[1] /= scale; } - - if (springLoaded) { - size[0] *= shrinkFactor; - size[1] *= shrinkFactor; - } return size; } else { size[0] = Integer.MAX_VALUE; @@ -408,11 +397,15 @@ public class Workspace extends PagedView } if (mOutlineProvider != null) { - // The outline is used to visualize where the item will land if dropped - mOutlineProvider.generateDragOutline(mCanvas); + if (dragObject.dragView != null) { + Bitmap preview = dragObject.dragView.getPreviewBitmap(); + + // The outline is used to visualize where the item will land if dropped + mOutlineProvider.generateDragOutline(preview); + } } - updateChildrenLayersEnabled(false); + updateChildrenLayersEnabled(); mLauncher.lockScreenOrientation(); mLauncher.onInteractionBegin(); // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging @@ -465,7 +458,7 @@ public class Workspace extends PagedView removeExtraEmptyScreen(true, mDragSourceInternal != null); } - updateChildrenLayersEnabled(false); + updateChildrenLayersEnabled(); mLauncher.unlockScreenOrientation(false); // Re-enable any Un/InstallShortcutReceiver and now process any queued items @@ -1022,10 +1015,6 @@ public class Workspace extends PagedView || (mTransitionProgress > FINISHED_SWITCHING_STATE_TRANSITION_PROGRESS); } - protected void onWindowVisibilityChanged (int visibility) { - mLauncher.onWindowVisibilityChanged(visibility); - } - @Override public boolean dispatchUnhandledMove(View focused, int direction) { if (workspaceInModalState() || !isFinishedSwitchingState()) { @@ -1054,30 +1043,6 @@ public class Workspace extends PagedView return super.onInterceptTouchEvent(ev); } - protected void reinflateWidgetsIfNecessary() { - final int clCount = getChildCount(); - for (int i = 0; i < clCount; i++) { - CellLayout cl = (CellLayout) getChildAt(i); - ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets(); - final int itemCount = swc.getChildCount(); - for (int j = 0; j < itemCount; j++) { - View v = swc.getChildAt(j); - - if (v instanceof LauncherAppWidgetHostView - && v.getTag() instanceof LauncherAppWidgetInfo) { - LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag(); - LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) v; - if (lahv.isReinflateRequired()) { - // Remove and rebind the current widget (which was inflated in the wrong - // orientation), but don't delete it from the database - mLauncher.removeItem(lahv, info, false /* deleteFromDb */); - mLauncher.bindAppWidget(info); - } - } - } - } - } - @Override protected void determineScrollingStart(MotionEvent ev) { if (!isFinishedSwitchingState()) return; @@ -1115,12 +1080,12 @@ public class Workspace extends PagedView protected void onPageBeginTransition() { super.onPageBeginTransition(); - updateChildrenLayersEnabled(false); + updateChildrenLayersEnabled(); } protected void onPageEndTransition() { super.onPageEndTransition(); - updateChildrenLayersEnabled(false); + updateChildrenLayersEnabled(); if (mDragController.isDragging()) { if (workspaceInModalState()) { @@ -1465,10 +1430,6 @@ public class Workspace extends PagedView mWallpaperOffset.setWindowToken(null); } - protected void onResume() { - mWallpaperOffset.onResume(); - } - @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (mUnlockWallpaperFromDefaultPageOnLayout) { @@ -1500,9 +1461,9 @@ public class Workspace extends PagedView return mState == State.NORMAL || mState == State.SPRING_LOADED; } - @Thunk void updateChildrenLayersEnabled(boolean force) { + private void updateChildrenLayersEnabled() { boolean small = mState == State.OVERVIEW || mIsSwitchingState; - boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageInTransition(); + boolean enableChildrenLayers = small || isPageInTransition(); if (enableChildrenLayers != mChildrenLayersEnabled) { mChildrenLayersEnabled = enableChildrenLayers; @@ -1568,19 +1529,6 @@ public class Workspace extends PagedView } } - public void buildPageHardwareLayers() { - // force layers to be enabled just for the call to buildLayer - updateChildrenLayersEnabled(true); - if (getWindowToken() != null) { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - CellLayout cl = (CellLayout) getChildAt(i); - cl.buildHardwareLayer(); - } - } - updateChildrenLayersEnabled(false); - } - protected void onWallpaperTap(MotionEvent ev) { final int[] position = mTempXY; getLocationOnScreen(position); @@ -1599,11 +1547,6 @@ public class Workspace extends PagedView mOutlineProvider = outlineProvider; } - public void exitWidgetResizeMode() { - DragLayer dragLayer = mLauncher.getDragLayer(); - dragLayer.clearResizeFrame(); - } - public void onStartReordering() { super.onStartReordering(); // Reordering handles its own animations, disable the automatic ones. @@ -1779,12 +1722,12 @@ public class Workspace extends PagedView } invalidate(); // This will call dispatchDraw(), which calls getVisiblePages(). - updateChildrenLayersEnabled(false); + updateChildrenLayersEnabled(); } public void onEndStateTransition() { mIsSwitchingState = false; - updateChildrenLayersEnabled(false); + updateChildrenLayersEnabled(); mForceDrawAdjacentPages = false; mTransitionProgress = 1; } @@ -1833,7 +1776,7 @@ public class Workspace extends PagedView mOutlineProvider = previewProvider; // The drag bitmap follows the touch point around on the screen - final Bitmap b = previewProvider.createDragBitmap(mCanvas); + final Bitmap b = previewProvider.createDragBitmap(); int halfPadding = previewProvider.previewPadding / 2; float scale = previewProvider.getScaleAndPosition(b, mTempXY); @@ -1880,8 +1823,7 @@ public class Workspace extends PagedView DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, dragObject, dragVisualizeOffset, dragRect, scale, dragOptions); - dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor()); - b.recycle(); + dv.setIntrinsicIconScaleFactor(dragOptions.intrinsicIconScaleFactor); return dv; } @@ -1893,6 +1835,7 @@ public class Workspace extends PagedView /** * {@inheritDoc} */ + @Override public boolean acceptDrop(DragObject d) { // If it's an external drop (e.g. from All Apps), check if it should be accepted CellLayout dropTargetLayout = mDropToLayout; @@ -2244,8 +2187,7 @@ public class Workspace extends PagedView mDelayedResizeRunnable = new Runnable() { public void run() { if (!isPageInTransition()) { - DragLayer dragLayer = mLauncher.getDragLayer(); - dragLayer.addResizeFrame(hostView, cellLayout); + AppWidgetResizeFrame.showForWidget(hostView, cellLayout); } } }; @@ -2269,16 +2211,6 @@ public class Workspace extends PagedView } final CellLayout parent = (CellLayout) cell.getParent().getParent(); - // Prepare it to be animated into its new position - // This must be called after the view has been re-parented - final Runnable onCompleteRunnable = new Runnable() { - @Override - public void run() { - mAnimatingViewIntoPlace = false; - updateChildrenLayersEnabled(false); - } - }; - mAnimatingViewIntoPlace = true; if (d.dragView.hasDrawn()) { if (droppedOnOriginalCellDuringTransition) { // Animate the item to its original position, while simultaneously exiting @@ -2297,12 +2229,11 @@ public class Workspace extends PagedView if (isWidget) { int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE : ANIMATE_INTO_POSITION_AND_DISAPPEAR; - animateWidgetDrop(info, parent, d.dragView, - onCompleteRunnable, animationType, cell, false); + animateWidgetDrop(info, parent, d.dragView, null, animationType, cell, false); } else { int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION; mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration, - onCompleteRunnable, this); + null, this); } } else { d.deferDragViewCleanupPostAnimation = false; @@ -2992,7 +2923,7 @@ public class Workspace extends PagedView } public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) { - int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo, false, true); + int[] unScaledSize = estimateItemSize(widgetInfo); int visibility = layout.getVisibility(); layout.setVisibility(VISIBLE); @@ -3000,12 +2931,9 @@ public class Workspace extends PagedView int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY); Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1], Bitmap.Config.ARGB_8888); - mCanvas.setBitmap(b); - layout.measure(width, height); layout.layout(0, 0, unScaledSize[0], unScaledSize[1]); - layout.draw(mCanvas); - mCanvas.setBitmap(null); + layout.draw(new Canvas(b)); layout.setVisibility(visibility); return b; } @@ -3157,7 +3085,7 @@ public class Workspace extends PagedView // hardware layers on children are enabled on startup, but should be disabled until // needed - updateChildrenLayersEnabled(false); + updateChildrenLayersEnabled(); } /** @@ -3256,21 +3184,6 @@ public class Workspace extends PagedView } } - @Override - public float getIntrinsicIconScaleFactor() { - return 1f; - } - - @Override - public boolean supportsAppInfoDropTarget() { - return true; - } - - @Override - public boolean supportsDeleteDropTarget() { - return true; - } - public boolean isDropEnabled() { return true; } @@ -3641,7 +3554,7 @@ public class Workspace extends PagedView .getInstance(mLauncher).findProvider(item.providerName, item.user); } else { widgetInfo = AppWidgetManagerCompat.getInstance(mLauncher) - .getAppWidgetInfo(item.appWidgetId); + .getLauncherAppWidgetInfo(item.appWidgetId); } if (widgetInfo != null) { diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 4eba5c6df..d63ae4189 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -115,13 +115,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc } /** - * Sets the current set of predicted apps. - */ - public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) { - mApps.setPredictedApps(apps); - } - - /** * Sets the current set of apps. */ public void setApps(List<AppInfo> apps) { @@ -290,24 +283,12 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc dragController.removeDragListener(this); } }); - mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions()); - return false; - } - @Override - public boolean supportsAppInfoDropTarget() { - return true; - } - - @Override - public boolean supportsDeleteDropTarget() { - return false; - } - - @Override - public float getIntrinsicIconScaleFactor() { DeviceProfile grid = mLauncher.getDeviceProfile(); - return (float) grid.allAppsIconSizePx / grid.iconSizePx; + DragOptions options = new DragOptions(); + options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx; + mLauncher.getWorkspace().beginDragShared(v, this, options); + return false; } @Override diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 3364c61ee..b844ba303 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -6,14 +6,11 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; -import android.graphics.Color; import android.support.animation.SpringAnimation; -import android.support.v4.graphics.ColorUtils; import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.view.MotionEvent; import android.view.View; import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import com.android.launcher3.AbstractFloatingView; @@ -46,12 +43,8 @@ import com.android.launcher3.util.TouchController; public class AllAppsTransitionController implements TouchController, SwipeDetector.Listener, SearchUiManager.OnScrollRangeChangeListener { - private static final String TAG = "AllAppsTrans"; - private static final boolean DBG = false; - private final Interpolator mWorkspaceAccelnterpolator = new AccelerateInterpolator(2f); private final Interpolator mHotseatAccelInterpolator = new AccelerateInterpolator(1.5f); - private final Interpolator mDecelInterpolator = new DecelerateInterpolator(3f); private final Interpolator mFastOutSlowInInterpolator = new FastOutSlowInInterpolator(); private final SwipeDetector.ScrollInterpolator mScrollInterpolator = new SwipeDetector.ScrollInterpolator(); @@ -60,10 +53,8 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect private static final int SINGLE_FRAME_MS = 16; private AllAppsContainerView mAppsView; - private int mAllAppsBackgroundColor; private Workspace mWorkspace; private Hotseat mHotseat; - private int mHotseatBackgroundColor; private AllAppsCaretController mCaretController; @@ -112,7 +103,6 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect mProgress = 1f; mEvaluator = new ArgbEvaluator(); - mAllAppsBackgroundColor = Themes.getAttrColor(l, android.R.attr.colorPrimary); mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark); } @@ -226,7 +216,7 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect Action.Direction.UP, containerType); } - mLauncher.showAppsView(true /* animated */, false /* updatePredictedApps */); + mLauncher.showAppsView(true /* animated */); if (hasSpringAnimationHandler()) { mSpringAnimationHandler.add(mSearchSpring, true /* setDefaultValues */); // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.) @@ -249,7 +239,7 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect Action.Direction.UP, containerType); } - mLauncher.showAppsView(true, /* animated */ false /* updatePredictedApps */); + mLauncher.showAppsView(true /* animated */); } } } @@ -266,29 +256,13 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect // Initialize values that should not change until #onDragEnd mStatusBarHeight = mLauncher.getDragLayer().getInsets().top; mHotseat.setVisibility(View.VISIBLE); - mHotseatBackgroundColor = mHotseat.getBackgroundDrawableColor(); - mHotseat.setBackgroundTransparent(true /* transparent */); - if (!mLauncher.isAllAppsVisible()) { - mLauncher.tryAndUpdatePredictedApps(); - mAppsView.setVisibility(View.VISIBLE); - if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - mAppsView.setRevealDrawableColor(mHotseatBackgroundColor); - } - } + mAppsView.setVisibility(View.VISIBLE); } } private void updateLightStatusBar(float shift) { - // Do not modify status bar on landscape as all apps is not full bleed. - if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS - && mLauncher.getDeviceProfile().isVerticalBarLayout()) { - return; - } - // Use a light system UI (dark icons) if all apps is behind at least half of the status bar. - boolean forceChange = FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS ? - shift <= mShiftRange / 4 : - shift <= mStatusBarHeight / 2; + boolean forceChange = shift <= mShiftRange / 4; if (forceChange) { mLauncher.getSystemUiController().updateUiState( SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme); @@ -301,8 +275,7 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect private void updateAllAppsBg(float progress) { // gradient if (mGradientView == null) { - mGradientView = (GradientView) mLauncher.findViewById(R.id.gradient_bg); - mGradientView.setVisibility(View.VISIBLE); + mGradientView = mLauncher.findViewById(R.id.gradient_bg); } mGradientView.setProgress(progress); } @@ -320,17 +293,7 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect float workspaceAlpha = mWorkspaceAccelnterpolator.getInterpolation(workspaceHotseatAlpha); float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha); - int color = (Integer) mEvaluator.evaluate(mDecelInterpolator.getInterpolation(alpha), - mHotseatBackgroundColor, mAllAppsBackgroundColor); - int bgAlpha = Color.alpha((int) mEvaluator.evaluate(alpha, - mHotseatBackgroundColor, mAllAppsBackgroundColor)); - - if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - updateAllAppsBg(alpha); - } else { - mAppsView.setRevealDrawableColor(ColorUtils.setAlphaComponent(color, bgAlpha)); - } - + updateAllAppsBg(alpha); mAppsView.getContentView().setAlpha(alpha); mAppsView.setTranslationY(shiftCurrent); @@ -530,7 +493,6 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect public void finishPullDown() { mAppsView.setVisibility(View.INVISIBLE); - mHotseat.setBackgroundTransparent(false /* transparent */); mHotseat.setVisibility(View.VISIBLE); mAppsView.reset(); if (hasSpringAnimationHandler()) { diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 6bbe3ea55..f0b650bd2 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -362,9 +362,12 @@ public class AlphabeticalAppsList { 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); + AdapterItem orgItem = mAdapterItems.get(i); + AdapterItem newItem = AdapterItem.asPredictedApp(orgItem.position, "", info, + orgItem.appIndex); + newItem.rowAppIndex = orgItem.rowAppIndex; + + mAdapterItems.set(i, newItem); mFilteredApps.set(i, info); mAdapter.notifyItemChanged(i); } diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java index 63aa7be3a..bf03a0ee1 100644 --- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java @@ -15,16 +15,13 @@ */ package com.android.launcher3.allapps.search; -import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; -import android.view.View; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; @@ -50,7 +47,6 @@ public class AllAppsSearchBarController protected String mQuery; protected SearchAlgorithm mSearchAlgorithm; - protected InputMethodManager mInputMethodManager; public void setVisibility(int visibility) { mInput.setVisibility(visibility); @@ -68,10 +64,6 @@ public class AllAppsSearchBarController mInput.addTextChangedListener(this); mInput.setOnEditorActionListener(this); mInput.setOnBackKeyListener(this); - - mInputMethodManager = (InputMethodManager) - mInput.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - mSearchAlgorithm = searchAlgorithm; } @@ -137,22 +129,9 @@ public class AllAppsSearchBarController * Resets the search bar state. */ public void reset() { - unfocusSearchField(); mCb.clearSearchResult(); - mInput.setText(""); + mInput.reset(); mQuery = null; - hideKeyboard(); - } - - protected void hideKeyboard() { - mInputMethodManager.hideSoftInputFromWindow(mInput.getWindowToken(), 0); - } - - protected void unfocusSearchField() { - View nextFocus = mInput.focusSearch(View.FOCUS_DOWN); - if (nextFocus != null) { - nextFocus.requestFocus(); - } } /** diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java index 4e00eae9d..fd1f0cca2 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java @@ -24,10 +24,13 @@ import android.os.Bundle; import android.os.UserHandle; import android.support.annotation.Nullable; +import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.widget.custom.CustomWidgetParser; import java.util.HashMap; import java.util.List; @@ -40,7 +43,7 @@ public abstract class AppWidgetManagerCompat { public static AppWidgetManagerCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { - if (Utilities.isAtLeastO()) { + if (Utilities.ATLEAST_OREO) { sInstance = new AppWidgetManagerCompatVO(context.getApplicationContext()); } else { sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext()); @@ -58,12 +61,13 @@ public abstract class AppWidgetManagerCompat { mAppWidgetManager = AppWidgetManager.getInstance(context); } - public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { - return mAppWidgetManager.getAppWidgetInfo(appWidgetId); - } - public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(int appWidgetId) { - AppWidgetProviderInfo info = getAppWidgetInfo(appWidgetId); + if (FeatureFlags.ENABLE_CUSTOM_WIDGETS + && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) { + return CustomWidgetParser.getWidgetProvider(mContext, appWidgetId); + } + + AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId); return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info); } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java index cb3bd6c7d..843028503 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java @@ -20,14 +20,17 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; import android.os.Bundle; +import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.support.annotation.Nullable; +import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.widget.custom.CustomWidgetParser; import java.util.ArrayList; import java.util.Collections; @@ -54,6 +57,10 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { for (UserHandle user : mUserManager.getUserProfiles()) { providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user)); } + + if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) { + providers.addAll(CustomWidgetParser.getCustomWidgets(mContext)); + } return providers; } // Only get providers for the given package/user. @@ -65,6 +72,11 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { iterator.remove(); } } + + if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(packageUser.mUser) + && mContext.getPackageName().equals(packageUser.mPackageName)) { + providers.addAll(CustomWidgetParser.getCustomWidgets(mContext)); + } return providers; } @@ -74,6 +86,11 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { if (FeatureFlags.GO_DISABLE_WIDGETS) { return false; } + + if (FeatureFlags.ENABLE_CUSTOM_WIDGETS + && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) { + return true; + } return mAppWidgetManager.bindAppWidgetIdIfAllowed( appWidgetId, info.getProfile(), info.provider, options); } @@ -89,6 +106,15 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info); } } + + if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(user)) { + for (LauncherAppWidgetProviderInfo info : + CustomWidgetParser.getCustomWidgets(mContext)) { + if (info.provider.equals(provider)) { + return info; + } + } + } return null; } @@ -104,6 +130,13 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { result.put(new ComponentKey(info.provider, user), info); } } + + if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) { + for (LauncherAppWidgetProviderInfo info : + CustomWidgetParser.getCustomWidgets(mContext)) { + result.put(new ComponentKey(info.provider, info.getProfile()), info); + } + } return result; } } diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java index 75a2a5d18..2cac536f6 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompat.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java @@ -53,7 +53,7 @@ public abstract class LauncherAppsCompat { public static LauncherAppsCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { - if (Utilities.isAtLeastO()) { + if (Utilities.ATLEAST_OREO) { sInstance = new LauncherAppsCompatVO(context.getApplicationContext()); } else { sInstance = new LauncherAppsCompatVL(context.getApplicationContext()); diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompat.java b/src/com/android/launcher3/compat/WallpaperManagerCompat.java index cbcabdf9b..00258c7da 100644 --- a/src/com/android/launcher3/compat/WallpaperManagerCompat.java +++ b/src/com/android/launcher3/compat/WallpaperManagerCompat.java @@ -31,10 +31,10 @@ public abstract class WallpaperManagerCompat { if (sInstance == null) { context = context.getApplicationContext(); - if (Utilities.isAtLeastO()) { + if (Utilities.ATLEAST_OREO) { try { sInstance = new WallpaperManagerCompatVOMR1(context); - } catch (Exception e) { + } catch (Throwable e) { // The wallpaper APIs do not yet exist } } diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java b/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java index 8e572ee1a..4cc70d367 100644 --- a/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java +++ b/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java @@ -15,6 +15,10 @@ */ package com.android.launcher3.compat; +import static android.app.WallpaperManager.FLAG_SYSTEM; + +import static com.android.launcher3.Utilities.getDevicePrefs; + import android.app.WallpaperInfo; import android.app.WallpaperManager; import android.app.job.JobInfo; @@ -38,7 +42,6 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; import android.support.annotation.Nullable; -import android.support.v7.graphics.Palette; import android.util.Log; import android.util.Pair; @@ -46,12 +49,6 @@ import com.android.launcher3.Utilities; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import static android.app.WallpaperManager.FLAG_SYSTEM; -import static com.android.launcher3.Utilities.getDevicePrefs; public class WallpaperManagerCompatVL extends WallpaperManagerCompat { @@ -260,27 +257,8 @@ public class WallpaperManagerCompatVL extends WallpaperManagerCompat { String value = VERSION_PREFIX + wallpaperId; if (bitmap != null) { - Palette palette = Palette.from(bitmap).generate(); - bitmap.recycle(); - - StringBuilder builder = new StringBuilder(value); - List<Pair<Integer,Integer>> colorsToOccurrences = new ArrayList<>(); - for (Palette.Swatch swatch : palette.getSwatches()) { - colorsToOccurrences.add(new Pair(swatch.getRgb(), swatch.getPopulation())); - } - - Collections.sort(colorsToOccurrences, new Comparator<Pair<Integer, Integer>>() { - @Override - public int compare(Pair<Integer, Integer> a, Pair<Integer, Integer> b) { - return b.second - a.second; - } - }); - - for (int i=0; i < Math.min(3, colorsToOccurrences.size()); i++) { - builder.append(',').append(colorsToOccurrences.get(i).first); - } - - value = builder.toString(); + int color = Utilities.findDominantColorByHue(bitmap, MAX_WALLPAPER_EXTRACTION_AREA); + value += "," + color; } // Send the result diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java b/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java index 28b780a38..524f266fc 100644 --- a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java +++ b/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java @@ -35,8 +35,9 @@ public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat { private final WallpaperManager mWm; private Method mWCColorHintsMethod; - WallpaperManagerCompatVOMR1(Context context) throws Exception { + WallpaperManagerCompatVOMR1(Context context) throws Throwable { mWm = context.getSystemService(WallpaperManager.class); + String className = WallpaperColors.class.getName(); try { mWCColorHintsMethod = WallpaperColors.class.getDeclaredMethod("getColorHints"); } catch (Exception exc) { diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 5adeec1c6..8a1bc6388 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -39,8 +39,6 @@ abstract class BaseFlags { 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 - public static final boolean LAUNCHER3_GRADIENT_ALL_APPS = true; // When enabled allows use of physics based motions in the Launcher. public static final boolean LAUNCHER3_PHYSICS = true; // When enabled allows use of spring motions on the icons. @@ -50,16 +48,15 @@ abstract class BaseFlags { public static final boolean QSB_ON_FIRST_SCREEN = true; // When enabled the all-apps icon is not added to the hotseat. public static final boolean NO_ALL_APPS_ICON = true; - // When enabled the status bar may show dark icons based on the top of the wallpaper. - public static final boolean LIGHT_STATUS_BAR = false; // When enabled, icons not supporting {@link AdaptiveIconDrawable} will be wrapped in {@link FixedScaleDrawable}. public static final boolean LEGACY_ICON_TREATMENT = true; // When enabled, adaptive icons would have shadows baked when being stored to icon cache. public static final boolean ADAPTIVE_ICON_SHADOW = true; // When enabled, app discovery will be enabled if service is implemented public static final boolean DISCOVERY_ENABLED = false; - // When enabled, the qsb will be moved to the hotseat. - public static final boolean QSB_IN_HOTSEAT = true; + + // When true, custom widgets are loaded using CustomWidgetParser. + public static final boolean ENABLE_CUSTOM_WIDGETS = false; // Features to control Launcher3Go behavior public static final boolean GO_DISABLE_WIDGETS = false; diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java index d0f2629aa..727fb51ce 100644 --- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java @@ -159,21 +159,6 @@ public abstract class BaseItemDragListener implements } @Override - public boolean supportsAppInfoDropTarget() { - return false; - } - - @Override - public boolean supportsDeleteDropTarget() { - return false; - } - - @Override - public float getIntrinsicIconScaleFactor() { - return 1f; - } - - @Override public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete, boolean success) { if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() && diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index b8527148b..a7ed87fb6 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -27,7 +27,6 @@ import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.inputmethod.InputMethodManager; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; @@ -39,6 +38,7 @@ import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.TouchController; +import com.android.launcher3.util.UiThreadHelper; import java.util.ArrayList; @@ -138,8 +138,7 @@ public class DragController implements DragDriver.EventListener, TouchController } // Hide soft keyboard, if visible - mLauncher.getSystemService(InputMethodManager.class) - .hideSoftInputFromWindow(mWindowToken, 0); + UiThreadHelper.hideKeyboardAsync(mLauncher, mWindowToken); mOptions = options; if (mOptions.systemDndStartPoint != null) { diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index fde7995ce..60ce3c36a 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -24,13 +24,11 @@ import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Rect; import android.graphics.Region; import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -42,13 +40,10 @@ import android.widget.FrameLayout; import android.widget.TextView; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.AppWidgetResizeFrame; import com.android.launcher3.CellLayout; import com.android.launcher3.DropTargetBar; -import com.android.launcher3.ExtendedEditText; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppWidgetHostView; import com.android.launcher3.PinchToOverviewListener; import com.android.launcher3.R; import com.android.launcher3.ShortcutAndWidgetContainer; @@ -59,11 +54,9 @@ import com.android.launcher3.dynamicui.WallpaperColorInfo; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.keyboard.ViewGroupFocusHelper; -import com.android.launcher3.logging.LoggerUtils; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.TouchController; -import com.android.launcher3.widget.WidgetsBottomSheet; import java.util.ArrayList; @@ -81,10 +74,6 @@ public class DragLayer extends InsettableFrameLayout { private Launcher mLauncher; - // Variables relating to resizing widgets - private final boolean mIsRtl; - private AppWidgetResizeFrame mCurrentResizeFrame; - // Variables relating to animation of views after drop private ValueAnimator mDropAnim = null; private final TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f); @@ -105,7 +94,6 @@ public class DragLayer extends InsettableFrameLayout { private float mBackgroundAlpha = 0; // Related to adjacent page hints - private final Rect mScrollChildPosition = new Rect(); private final ViewGroupFocusHelper mFocusIndicatorHelper; private final WallpaperColorInfo mWallpaperColorInfo; @@ -129,7 +117,6 @@ public class DragLayer extends InsettableFrameLayout { setMotionEventSplittingEnabled(false); setChildrenDrawingOrderEnabled(true); - mIsRtl = Utilities.isRtl(getResources()); mFocusIndicatorHelper = new ViewGroupFocusHelper(this); mWallpaperColorInfo = WallpaperColorInfo.getInstance(getContext()); } @@ -159,10 +146,6 @@ public class DragLayer extends InsettableFrameLayout { ? null : new PinchToOverviewListener(mLauncher); } - public boolean isEventOverPageIndicator(MotionEvent ev) { - return isEventOverView(mLauncher.getWorkspace().getPageIndicator(), ev); - } - public boolean isEventOverHotseat(MotionEvent ev) { return isEventOverView(mLauncher.getHotseat(), ev); } @@ -180,36 +163,6 @@ public class DragLayer extends InsettableFrameLayout { return mHitRect.contains((int) ev.getX(), (int) ev.getY()); } - private boolean handleTouchDown(MotionEvent ev, boolean intercept) { - AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher); - if (topView != null && intercept) { - ExtendedEditText textView = topView.getActiveTextView(); - if (textView != null) { - if (!isEventOverView(textView, ev)) { - textView.dispatchBackKey(); - return true; - } - } else if (!isEventOverView(topView, ev)) { - if (isInAccessibleDrag()) { - // Do not close the container if in drag and drop. - if (!isEventOverDropTargetBar(ev)) { - return true; - } - } else { - mLauncher.getUserEventDispatcher().logActionTapOutside( - LoggerUtils.newContainerTarget(topView.getLogContainerType())); - topView.close(true); - - // We let touches on the original icon go through so that users can launch - // the app with one tap if they don't find a shortcut they want. - View extendedTouch = topView.getExtendedTouchView(); - return extendedTouch == null || !isEventOverView(extendedTouch, ev); - } - } - } - return false; - } - @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); @@ -219,9 +172,6 @@ public class DragLayer extends InsettableFrameLayout { // dray layer even if mAllAppsController is NOT the active controller. // TODO: handle other input other than touch mAllAppsController.cancelDiscoveryAnimation(); - if (handleTouchDown(ev, true)) { - return true; - } } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (mTouchCompleteListener != null) { mTouchCompleteListener.onTouchComplete(); @@ -230,12 +180,10 @@ public class DragLayer extends InsettableFrameLayout { } mActiveController = null; - if (mCurrentResizeFrame != null - && mCurrentResizeFrame.onControllerInterceptTouchEvent(ev)) { - mActiveController = mCurrentResizeFrame; + AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher); + if (topView != null && topView.onControllerInterceptTouchEvent(ev)) { + mActiveController = topView; return true; - } else { - clearResizeFrame(); } if (mDragController.onControllerInterceptTouchEvent(ev)) { @@ -248,12 +196,6 @@ public class DragLayer extends InsettableFrameLayout { return true; } - WidgetsBottomSheet widgetsBottomSheet = WidgetsBottomSheet.getOpen(mLauncher); - if (widgetsBottomSheet != null && widgetsBottomSheet.onControllerInterceptTouchEvent(ev)) { - mActiveController = widgetsBottomSheet; - return true; - } - if (mPinchListener != null && mPinchListener.onControllerInterceptTouchEvent(ev)) { // Stop listening for scrolling etc. (onTouchEvent() handles the rest of the pinch.) mActiveController = mPinchListener; @@ -357,12 +299,7 @@ public class DragLayer extends InsettableFrameLayout { @Override public boolean onTouchEvent(MotionEvent ev) { int action = ev.getAction(); - - if (action == MotionEvent.ACTION_DOWN) { - if (handleTouchDown(ev, false)) { - return true; - } - } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (mTouchCompleteListener != null) { mTouchCompleteListener.onTouchComplete(); } @@ -542,25 +479,6 @@ public class DragLayer extends InsettableFrameLayout { } } - public void clearResizeFrame() { - if (mCurrentResizeFrame != null) { - removeView(mCurrentResizeFrame); - mCurrentResizeFrame = null; - } - } - - public void addResizeFrame(LauncherAppWidgetHostView widget, CellLayout cellLayout) { - clearResizeFrame(); - - mCurrentResizeFrame = (AppWidgetResizeFrame) LayoutInflater.from(mLauncher) - .inflate(R.layout.app_widget_resize_frame, this, false); - mCurrentResizeFrame.setupForWidget(widget, cellLayout, this); - ((LayoutParams) mCurrentResizeFrame.getLayoutParams()).customPosition = true; - - addView(mCurrentResizeFrame); - mCurrentResizeFrame.snapToWidget(false); - } - public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha, float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable, int duration) { diff --git a/src/com/android/launcher3/dragndrop/DragOptions.java b/src/com/android/launcher3/dragndrop/DragOptions.java index 9433aadc7..f108f8b53 100644 --- a/src/com/android/launcher3/dragndrop/DragOptions.java +++ b/src/com/android/launcher3/dragndrop/DragOptions.java @@ -34,6 +34,9 @@ public class DragOptions { /** Determines when a pre-drag should transition to a drag. By default, this is immediate. */ public PreDragCondition preDragCondition = null; + /** Scale of the icons over the workspace icon size. */ + public float intrinsicIconScaleFactor = 1f; + /** * Specifies a condition that must be met before DragListener#onDragStart() is called. * By default, there is no condition and onDragStart() is called immediately following diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index e81e2a386..17fad8496 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -169,7 +169,7 @@ public class DragView extends View { } }); - mBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight()); + mBitmap = bitmap; setDragRegion(new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight())); // The point in our scaled bitmap that the touch events are located @@ -193,7 +193,7 @@ public class DragView extends View { */ @TargetApi(Build.VERSION_CODES.O) public void setItemInfo(final ItemInfo info) { - if (!(FeatureFlags.LAUNCHER3_SPRING_ICONS && Utilities.isAtLeastO())) { + if (!(FeatureFlags.LAUNCHER3_SPRING_ICONS && Utilities.ATLEAST_OREO)) { return; } if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && @@ -427,6 +427,10 @@ public class DragView extends View { return mDragRegion; } + public Bitmap getPreviewBitmap() { + return mBitmap; + } + @Override protected void onDraw(Canvas canvas) { mHasDrawn = true; diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java index c8d3890ba..b9d97ac5a 100644 --- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java @@ -128,7 +128,7 @@ public class PinItemDragListener extends BaseItemDragListener implements Parcela } public static boolean handleDragRequest(Launcher launcher, Intent intent) { - if (!Utilities.isAtLeastO()) { + if (!Utilities.ATLEAST_OREO) { return false; } if (intent == null || !Intent.ACTION_MAIN.equals(intent.getAction())) { diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionService.java b/src/com/android/launcher3/dynamicui/ColorExtractionService.java deleted file mode 100644 index b9dd3b588..000000000 --- a/src/com/android/launcher3/dynamicui/ColorExtractionService.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.dynamicui; - -import android.annotation.TargetApi; -import android.app.WallpaperManager; -import android.app.job.JobParameters; -import android.app.job.JobService; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.BitmapRegionDecoder; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.ParcelFileDescriptor; -import android.support.v7.graphics.Palette; -import android.util.Log; - -import com.android.launcher3.LauncherProvider; -import com.android.launcher3.LauncherSettings; -import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; - -import java.io.IOException; - -/** - * Extracts colors from the wallpaper, and saves results to {@link LauncherProvider}. - */ -public class ColorExtractionService extends JobService { - - private static final String TAG = "ColorExtractionService"; - private static final boolean DEBUG = false; - - /** The fraction of the wallpaper to extract colors for use on the hotseat. */ - private static final float HOTSEAT_FRACTION = 1f / 4; - - private HandlerThread mWorkerThread; - private Handler mWorkerHandler; - - @Override - public void onCreate() { - super.onCreate(); - mWorkerThread = new HandlerThread("ColorExtractionService"); - mWorkerThread.start(); - mWorkerHandler = new Handler(mWorkerThread.getLooper()); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mWorkerThread.quit(); - } - - @Override - public boolean onStartJob(final JobParameters jobParameters) { - if (DEBUG) Log.d(TAG, "onStartJob"); - mWorkerHandler.post(new Runnable() { - @Override - public void run() { - WallpaperManager wallpaperManager = WallpaperManager.getInstance( - ColorExtractionService.this); - int wallpaperId = ExtractionUtils.getWallpaperId(wallpaperManager); - - ExtractedColors extractedColors = new ExtractedColors(); - if (wallpaperManager.getWallpaperInfo() != null) { - // We can't extract colors from live wallpapers; always use the default color. - extractedColors.updateHotseatPalette(null); - - if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - extractedColors.updateWallpaperThemePalette(null); - } - } else { - // We extract colors for the hotseat and status bar separately, - // since they only consider part of the wallpaper. - extractedColors.updateHotseatPalette(getHotseatPalette()); - - if (FeatureFlags.LIGHT_STATUS_BAR) { - extractedColors.updateStatusBarPalette(getStatusBarPalette()); - } - - if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - extractedColors.updateWallpaperThemePalette(getWallpaperPalette()); - } - } - - // Save the extracted colors and wallpaper id to LauncherProvider. - String colorsString = extractedColors.encodeAsString(); - Bundle extras = new Bundle(); - extras.putInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID, wallpaperId); - extras.putString(LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS, colorsString); - getContentResolver().call( - LauncherSettings.Settings.CONTENT_URI, - LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID, - null, extras); - jobFinished(jobParameters, false /* needsReschedule */); - if (DEBUG) Log.d(TAG, "job finished!"); - } - }); - return true; - } - - @Override - public boolean onStopJob(JobParameters jobParameters) { - if (DEBUG) Log.d(TAG, "onStopJob"); - mWorkerHandler.removeCallbacksAndMessages(null); - return true; - } - - @TargetApi(Build.VERSION_CODES.N) - private Palette getHotseatPalette() { - WallpaperManager wallpaperManager = WallpaperManager.getInstance(this); - if (Utilities.ATLEAST_NOUGAT) { - try (ParcelFileDescriptor fd = wallpaperManager - .getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) { - BitmapRegionDecoder decoder = BitmapRegionDecoder - .newInstance(fd.getFileDescriptor(), false); - int height = decoder.getHeight(); - Rect decodeRegion = new Rect(0, (int) (height * (1f - HOTSEAT_FRACTION)), - decoder.getWidth(), height); - Bitmap bitmap = decoder.decodeRegion(decodeRegion, null); - decoder.recycle(); - if (bitmap != null) { - return Palette.from(bitmap).clearFilters().generate(); - } - } catch (IOException | NullPointerException e) { - Log.e(TAG, "Fetching partial bitmap failed, trying old method", e); - } - } - - Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap(); - return Palette.from(wallpaper) - .setRegion(0, (int) (wallpaper.getHeight() * (1f - HOTSEAT_FRACTION)), - wallpaper.getWidth(), wallpaper.getHeight()) - .clearFilters() - .generate(); - } - - @TargetApi(Build.VERSION_CODES.N) - private Palette getStatusBarPalette() { - WallpaperManager wallpaperManager = WallpaperManager.getInstance(this); - int statusBarHeight = getResources() - .getDimensionPixelSize(R.dimen.status_bar_height); - - if (Utilities.ATLEAST_NOUGAT) { - try (ParcelFileDescriptor fd = wallpaperManager - .getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) { - BitmapRegionDecoder decoder = BitmapRegionDecoder - .newInstance(fd.getFileDescriptor(), false); - Rect decodeRegion = new Rect(0, 0, - decoder.getWidth(), statusBarHeight); - Bitmap bitmap = decoder.decodeRegion(decodeRegion, null); - decoder.recycle(); - if (bitmap != null) { - return Palette.from(bitmap).clearFilters().generate(); - } - } catch (IOException | NullPointerException e) { - Log.e(TAG, "Fetching partial bitmap failed, trying old method", e); - } - } - - Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap(); - return Palette.from(wallpaper) - .setRegion(0, 0, wallpaper.getWidth(), statusBarHeight) - .clearFilters() - .generate(); - } - - @TargetApi(Build.VERSION_CODES.N) - private Palette getWallpaperPalette() { - WallpaperManager wallpaperManager = WallpaperManager.getInstance(this); - if (Utilities.ATLEAST_NOUGAT) { - try (ParcelFileDescriptor fd = wallpaperManager - .getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) { - Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor()); - if (bitmap != null) { - return Palette.from(bitmap).clearFilters().generate(); - } - } catch (IOException | NullPointerException e) { - Log.e(TAG, "Fetching partial bitmap failed, trying old method", e); - } - } - - Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap(); - return Palette.from(wallpaper).clearFilters().generate(); - } -} diff --git a/src/com/android/launcher3/dynamicui/ExtractedColors.java b/src/com/android/launcher3/dynamicui/ExtractedColors.java deleted file mode 100644 index 2d8bb869f..000000000 --- a/src/com/android/launcher3/dynamicui/ExtractedColors.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.dynamicui; - -import android.app.WallpaperManager; -import android.content.Context; -import android.graphics.Color; -import android.support.annotation.Nullable; -import android.support.v4.graphics.ColorUtils; -import android.support.v7.graphics.Palette; -import android.util.Log; - -import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; - -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Saves and loads colors extracted from the wallpaper, as well as the associated wallpaper id. - */ -public class ExtractedColors { - private static final String TAG = "ExtractedColors"; - - public static final int DEFAULT_LIGHT = Color.WHITE; - public static final int DEFAULT_DARK = Color.BLACK; - - // These color profile indices should NOT be changed, since they are used when saving and - // loading extracted colors. New colors should always be added at the end. - public static final int VERSION_INDEX = 0; - public static final int HOTSEAT_INDEX = 1; - public static final int STATUS_BAR_INDEX = 2; - public static final int WALLPAPER_VIBRANT_INDEX = 3; - public static final int ALLAPPS_GRADIENT_MAIN_INDEX = 4; - public static final int ALLAPPS_GRADIENT_SECONDARY_INDEX = 5; - - private static final int VERSION; - private static final int[] DEFAULT_VALUES; - - static { - if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - VERSION = 3; - DEFAULT_VALUES = new int[] { - VERSION, // VERSION_INDEX - 0x40FFFFFF, // HOTSEAT_INDEX: White with 25% alpha - DEFAULT_DARK, // STATUS_BAR_INDEX - 0xFFCCCCCC, // WALLPAPER_VIBRANT_INDEX - 0xFF000000, // ALLAPPS_GRADIENT_MAIN_INDEX - 0xFF000000 // ALLAPPS_GRADIENT_SECONDARY_INDEX - }; - } else if (FeatureFlags.QSB_IN_HOTSEAT) { - VERSION = 2; - DEFAULT_VALUES = new int[] { - VERSION, // VERSION_INDEX - 0x40FFFFFF, // HOTSEAT_INDEX: White with 25% alpha - DEFAULT_DARK, // STATUS_BAR_INDEX - 0xFFCCCCCC, // WALLPAPER_VIBRANT_INDEX - }; - } else { - VERSION = 1; - DEFAULT_VALUES = new int[] { - VERSION, // VERSION_INDEX - 0x40FFFFFF, // HOTSEAT_INDEX: White with 25% alpha - DEFAULT_DARK, // STATUS_BAR_INDEX - }; - } - } - - private static final String COLOR_SEPARATOR = ","; - - private final ArrayList<OnChangeListener> mListeners = new ArrayList<>(); - private final int[] mColors; - - public ExtractedColors() { - // The first entry is reserved for the version number. - mColors = Arrays.copyOf(DEFAULT_VALUES, DEFAULT_VALUES.length); - } - - public void setColorAtIndex(int index, int color) { - if (index > VERSION_INDEX && index < mColors.length) { - mColors[index] = color; - } else { - Log.e(TAG, "Attempted to set a color at an invalid index " + index); - } - } - - /** - * Encodes {@link #mColors} as a comma-separated String. - */ - String encodeAsString() { - StringBuilder colorsStringBuilder = new StringBuilder(); - for (int color : mColors) { - colorsStringBuilder.append(color).append(COLOR_SEPARATOR); - } - return colorsStringBuilder.toString(); - } - - /** - * Loads colors and wallpaper id from {@link Utilities#getPrefs(Context)}. - * These were saved there in {@link ColorExtractionService}. - */ - public void load(Context context) { - String encodedString = Utilities.getPrefs(context).getString( - ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, VERSION + ""); - - String[] splitColorsString = encodedString.split(COLOR_SEPARATOR); - if (splitColorsString.length == DEFAULT_VALUES.length && - Integer.parseInt(splitColorsString[VERSION_INDEX]) == VERSION) { - // Parse and apply the saved values. - for (int i = 0; i < mColors.length; i++) { - mColors[i] = Integer.parseInt(splitColorsString[i]); - } - } else { - // Leave the values as default values as the saved values may not be compatible. - ExtractionUtils.startColorExtractionService(context); - } - } - - /** @param index must be one of the index values defined at the top of this class. */ - public int getColor(int index) { - return mColors[index]; - } - - /** - * The hotseat's color is defined as follows: - * - 12% black for super light wallpaper - * - 18% white for super dark - * - 25% white otherwise - */ - public void updateHotseatPalette(Palette hotseatPalette) { - int hotseatColor; - if (hotseatPalette != null && ExtractionUtils.isSuperLight(hotseatPalette)) { - hotseatColor = ColorUtils.setAlphaComponent(Color.BLACK, (int) (0.12f * 255)); - } else if (hotseatPalette != null && ExtractionUtils.isSuperDark(hotseatPalette)) { - hotseatColor = ColorUtils.setAlphaComponent(Color.WHITE, (int) (0.18f * 255)); - } else { - hotseatColor = DEFAULT_VALUES[HOTSEAT_INDEX]; - } - setColorAtIndex(HOTSEAT_INDEX, hotseatColor); - } - - public void updateStatusBarPalette(Palette statusBarPalette) { - setColorAtIndex(STATUS_BAR_INDEX, ExtractionUtils.isSuperLight(statusBarPalette) ? - DEFAULT_LIGHT : DEFAULT_DARK); - } - - public void updateWallpaperThemePalette(@Nullable Palette wallpaperPalette) { - int defaultColor = DEFAULT_VALUES[WALLPAPER_VIBRANT_INDEX]; - setColorAtIndex(WALLPAPER_VIBRANT_INDEX, wallpaperPalette == null - ? defaultColor : wallpaperPalette.getVibrantColor(defaultColor)); - } - - public void addOnChangeListener(OnChangeListener listener) { - mListeners.add(listener); - } - - public void notifyChange() { - for (OnChangeListener listener : mListeners) { - listener.onExtractedColorsChanged(); - } - } - - /** - * Interface for listening for extracted color changes - */ - public interface OnChangeListener { - - void onExtractedColorsChanged(); - } -} diff --git a/src/com/android/launcher3/dynamicui/ExtractionUtils.java b/src/com/android/launcher3/dynamicui/ExtractionUtils.java deleted file mode 100644 index cc0e0bed1..000000000 --- a/src/com/android/launcher3/dynamicui/ExtractionUtils.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.dynamicui; - -import android.annotation.TargetApi; -import android.app.WallpaperManager; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.content.ComponentName; -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Color; -import android.os.Build; -import android.support.v4.graphics.ColorUtils; -import android.support.v7.graphics.Palette; - -import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; - -import java.util.List; - -/** - * Contains helper fields and methods related to extracting colors from the wallpaper. - */ -public class ExtractionUtils { - public static final String EXTRACTED_COLORS_PREFERENCE_KEY = "pref_extractedColors"; - public static final String WALLPAPER_ID_PREFERENCE_KEY = "pref_wallpaperId"; - - private static final float MIN_CONTRAST_RATIO = 2f; - - /** - * Extract colors in the :wallpaper-chooser process, if the wallpaper id has changed. - * When the new colors are saved in the LauncherProvider, - * Launcher will be notified in Launcher#onSettingsChanged(String, String). - */ - public static void startColorExtractionServiceIfNecessary(final Context context) { - if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - return; - } - // Run on a background thread, since the service is asynchronous anyway. - Utilities.THREAD_POOL_EXECUTOR.execute(new Runnable() { - @Override - public void run() { - if (hasWallpaperIdChanged(context)) { - startColorExtractionService(context); - } - } - }); - } - - /** Starts the {@link ColorExtractionService} without checking the wallpaper id */ - public static void startColorExtractionService(Context context) { - if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - return; - } - JobScheduler jobScheduler = (JobScheduler) context.getSystemService( - Context.JOB_SCHEDULER_SERVICE); - jobScheduler.schedule(new JobInfo.Builder(Utilities.COLOR_EXTRACTION_JOB_ID, - new ComponentName(context, ColorExtractionService.class)) - .setMinimumLatency(0).build()); - } - - private static boolean hasWallpaperIdChanged(Context context) { - if (!Utilities.ATLEAST_NOUGAT) { - // TODO: update an id in sharedprefs in onWallpaperChanged broadcast, and read it here. - return false; - } - final SharedPreferences sharedPrefs = Utilities.getPrefs(context); - int wallpaperId = getWallpaperId(WallpaperManager.getInstance(context)); - int savedWallpaperId = sharedPrefs.getInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, -1); - return wallpaperId != savedWallpaperId; - } - - @TargetApi(Build.VERSION_CODES.N) - public static int getWallpaperId(WallpaperManager wallpaperManager) { - return Utilities.ATLEAST_NOUGAT ? - wallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM) : -1; - } - - public static boolean isSuperLight(Palette p) { - return !isLegibleOnWallpaper(Color.WHITE, p.getSwatches()); - } - - public static boolean isSuperDark(Palette p) { - return !isLegibleOnWallpaper(Color.BLACK, p.getSwatches()); - } - - /** - * Given a color, returns true if that color is legible on - * the given wallpaper color swatches, else returns false. - */ - private static boolean isLegibleOnWallpaper(int color, List<Palette.Swatch> wallpaperSwatches) { - int legiblePopulation = 0; - int illegiblePopulation = 0; - for (Palette.Swatch swatch : wallpaperSwatches) { - if (isLegible(color, swatch.getRgb())) { - legiblePopulation += swatch.getPopulation(); - } else { - illegiblePopulation += swatch.getPopulation(); - } - } - return legiblePopulation > illegiblePopulation; - } - - /** @return Whether the foreground color is legible on the background color. */ - private static boolean isLegible(int foreground, int background) { - background = ColorUtils.setAlphaComponent(background, 255); - return ColorUtils.calculateContrast(foreground, background) >= MIN_CONTRAST_RATIO; - } - -} diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index b7f8f3e2e..0932b7411 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -32,6 +32,7 @@ import android.view.FocusFinder; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; import android.view.accessibility.AccessibilityEvent; @@ -66,6 +67,7 @@ import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragController.DragListener; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.logging.LoggerUtils; import com.android.launcher3.pageindicators.PageIndicatorDots; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; @@ -368,11 +370,6 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC return false; } - @Override - public ExtendedEditText getActiveTextView() { - return isEditingName() ? mFolderName : null; - } - public FolderIcon getFolderIcon() { return mFolderIcon; } @@ -709,6 +706,7 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC mContent.setCurrentPage(0); } + @Override public boolean acceptDrop(DragObject d) { final ItemInfo item = d.dragInfo; final int itemType = item.itemType; @@ -941,21 +939,6 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC } } - @Override - public float getIntrinsicIconScaleFactor() { - return 1f; - } - - @Override - public boolean supportsAppInfoDropTarget() { - return true; - } - - @Override - public boolean supportsDeleteDropTarget() { - return true; - } - private void updateItemLocationsInDatabaseBatch() { ArrayList<View> list = getItemsInReadingOrder(); ArrayList<ItemInfo> items = new ArrayList<ItemInfo>(); @@ -1532,7 +1515,45 @@ public class Folder extends AbstractFloatingView implements DragSource, View.OnC } @Override - public int getLogContainerType() { - return ContainerType.FOLDER; + public void logActionCommand(int command) { + mLauncher.getUserEventDispatcher().logActionCommand( + command, getFolderIcon(), ContainerType.FOLDER); + } + + @Override + public void onBackPressed() { + if (isEditingName()) { + mFolderName.dispatchBackKey(); + } else { + super.onBackPressed(); + } + } + + @Override + public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + DragLayer dl = mLauncher.getDragLayer(); + + if (isEditingName()) { + if (!dl.isEventOverView(mFolderName, ev)) { + mFolderName.dispatchBackKey(); + return true; + } + return false; + } else if (!dl.isEventOverView(this, ev)) { + if (mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) { + // Do not close the container if in drag and drop. + if (!dl.isEventOverView(mLauncher.getDropTargetBar(), ev)) { + return true; + } + } else { + mLauncher.getUserEventDispatcher().logActionTapOutside( + LoggerUtils.newContainerTarget(ContainerType.FOLDER)); + close(true); + return true; + } + } + } + return false; } } diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java index 10e91c0a8..355c231f3 100644 --- a/src/com/android/launcher3/graphics/DragPreviewProvider.java +++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java @@ -18,10 +18,15 @@ package com.android.launcher3.graphics; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BlurMaskFilter; import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Region.Op; import android.graphics.drawable.Drawable; +import android.os.Handler; import android.view.View; import com.android.launcher3.BubbleTextView; @@ -30,6 +35,9 @@ import com.android.launcher3.LauncherAppWidgetHostView; import com.android.launcher3.R; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.util.UiThreadHelper; + +import java.nio.ByteBuffer; /** * A utility class to generate preview bitmap for dragging. @@ -45,6 +53,7 @@ public class DragPreviewProvider { protected final int blurSizeOutline; + private OutlineGeneratorCallback mOutlineGeneratorCallback; public Bitmap generatedDragOutline; public DragPreviewProvider(View view) { @@ -106,7 +115,7 @@ public class DragPreviewProvider { * Returns a new bitmap to show when the {@link #mView} is being dragged around. * Responsibility for the bitmap is transferred to the caller. */ - public Bitmap createDragBitmap(Canvas canvas) { + public Bitmap createDragBitmap() { float scale = 1f; int width = mView.getWidth(); int height = mView.getHeight(); @@ -124,7 +133,7 @@ public class DragPreviewProvider { Bitmap b = Bitmap.createBitmap(width + blurSizeOutline, height + blurSizeOutline, Bitmap.Config.ARGB_8888); - canvas.setBitmap(b); + Canvas canvas = new Canvas(b); canvas.save(); canvas.scale(scale, scale); @@ -136,43 +145,13 @@ public class DragPreviewProvider { return b; } - public final void generateDragOutline(Canvas canvas) { - if (FeatureFlags.IS_DOGFOOD_BUILD && generatedDragOutline != null) { + public final void generateDragOutline(Bitmap preview) { + if (FeatureFlags.IS_DOGFOOD_BUILD && mOutlineGeneratorCallback != null) { throw new RuntimeException("Drag outline generated twice"); } - generatedDragOutline = createDragOutline(canvas); - } - - /** - * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. - * Responsibility for the bitmap is transferred to the caller. - */ - public Bitmap createDragOutline(Canvas canvas) { - float scale = 1f; - int width = mView.getWidth(); - int height = mView.getHeight(); - - if (mView instanceof LauncherAppWidgetHostView) { - scale = ((LauncherAppWidgetHostView) mView).getScaleToFit(); - width = (int) Math.floor(mView.getWidth() * scale); - height = (int) Math.floor(mView.getHeight() * scale); - } - - Bitmap b = Bitmap.createBitmap(width + blurSizeOutline, height + blurSizeOutline, - Bitmap.Config.ALPHA_8); - canvas.setBitmap(b); - - canvas.save(); - canvas.scale(scale, scale); - drawDragView(canvas); - canvas.restore(); - - HolographicOutlineHelper.getInstance(mView.getContext()) - .applyExpensiveOutlineWithBlur(b, canvas); - - canvas.setBitmap(null); - return b; + mOutlineGeneratorCallback = new OutlineGeneratorCallback(preview); + new Handler(UiThreadHelper.getBackgroundLooper()).post(mOutlineGeneratorCallback); } protected static Rect getDrawableBounds(Drawable d) { @@ -201,4 +180,89 @@ public class DragPreviewProvider { - previewPadding / 2); return scale; } + + protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) { + return preview.copy(Bitmap.Config.ALPHA_8, true); + } + + private class OutlineGeneratorCallback implements Runnable { + + private final Bitmap mPreviewSnapshot; + private final Context mContext; + + OutlineGeneratorCallback(Bitmap preview) { + mPreviewSnapshot = preview; + mContext = mView.getContext(); + } + + @Override + public void run() { + Bitmap preview = convertPreviewToAlphaBitmap(mPreviewSnapshot); + + // We start by removing most of the alpha channel so as to ignore shadows, and + // other types of partial transparency when defining the shape of the object + byte[] pixels = new byte[preview.getWidth() * preview.getHeight()]; + ByteBuffer buffer = ByteBuffer.wrap(pixels); + buffer.rewind(); + preview.copyPixelsToBuffer(buffer); + + for (int i = 0; i < pixels.length; i++) { + if ((pixels[i] & 0xFF) < 188) { + pixels[i] = 0; + } + } + + buffer.rewind(); + preview.copyPixelsFromBuffer(buffer); + + final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + Canvas canvas = new Canvas(); + + // calculate the outer blur first + paint.setMaskFilter(new BlurMaskFilter(blurSizeOutline, BlurMaskFilter.Blur.OUTER)); + int[] outerBlurOffset = new int[2]; + Bitmap thickOuterBlur = preview.extractAlpha(paint, outerBlurOffset); + + paint.setMaskFilter(new BlurMaskFilter( + mContext.getResources().getDimension(R.dimen.blur_size_thin_outline), + BlurMaskFilter.Blur.OUTER)); + int[] brightOutlineOffset = new int[2]; + Bitmap brightOutline = preview.extractAlpha(paint, brightOutlineOffset); + + // calculate the inner blur + canvas.setBitmap(preview); + canvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT); + paint.setMaskFilter(new BlurMaskFilter(blurSizeOutline, BlurMaskFilter.Blur.NORMAL)); + int[] thickInnerBlurOffset = new int[2]; + Bitmap thickInnerBlur = preview.extractAlpha(paint, thickInnerBlurOffset); + + // mask out the inner blur + paint.setMaskFilter(null); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + canvas.setBitmap(thickInnerBlur); + canvas.drawBitmap(preview, -thickInnerBlurOffset[0], + -thickInnerBlurOffset[1], paint); + canvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(), paint); + canvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1], paint); + + // draw the inner and outer blur + paint.setXfermode(null); + canvas.setBitmap(preview); + canvas.drawColor(0, PorterDuff.Mode.CLEAR); + canvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1], + paint); + canvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1], paint); + + // draw the bright outline + canvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1], paint); + + // cleanup + canvas.setBitmap(null); + brightOutline.recycle(); + thickOuterBlur.recycle(); + thickInnerBlur.recycle(); + + generatedDragOutline = preview; + } + } } diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java index 45344c020..371479b36 100644 --- a/src/com/android/launcher3/graphics/DrawableFactory.java +++ b/src/com/android/launcher3/graphics/DrawableFactory.java @@ -80,7 +80,7 @@ public class DrawableFactory { protected Path getPreloadProgressPath(Context context) { - if (Utilities.isAtLeastO()) { + if (Utilities.ATLEAST_OREO) { try { // Try to load the path from Mask Icon Drawable icon = context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper); diff --git a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java index b22182883..9e67f56e3 100644 --- a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java +++ b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java @@ -17,7 +17,6 @@ package com.android.launcher3.graphics; import android.content.Context; -import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; @@ -31,9 +30,6 @@ import android.util.SparseArray; import com.android.launcher3.BubbleTextView; import com.android.launcher3.R; -import com.android.launcher3.config.FeatureFlags; - -import java.nio.ByteBuffer; /** * Utility class to generate shadow and outline effect, which are used for click feedback @@ -44,14 +40,9 @@ public class HolographicOutlineHelper { private static HolographicOutlineHelper sInstance; private final Canvas mCanvas = new Canvas(); - private final Paint mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private final Paint mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); private final Paint mErasePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); - private final BlurMaskFilter mMediumOuterBlurMaskFilter; - private final BlurMaskFilter mThinOuterBlurMaskFilter; - private final BlurMaskFilter mMediumInnerBlurMaskFilter; - private final float mShadowBitmapShift; private final BlurMaskFilter mShadowBlurMaskFilter; @@ -59,18 +50,8 @@ public class HolographicOutlineHelper { private final SparseArray<Bitmap> mBitmapCache = new SparseArray<>(4); private HolographicOutlineHelper(Context context) { - Resources res = context.getResources(); - - float mediumBlur = res.getDimension(R.dimen.blur_size_medium_outline); - mMediumOuterBlurMaskFilter = new BlurMaskFilter(mediumBlur, BlurMaskFilter.Blur.OUTER); - mMediumInnerBlurMaskFilter = new BlurMaskFilter(mediumBlur, BlurMaskFilter.Blur.NORMAL); - - mThinOuterBlurMaskFilter = new BlurMaskFilter( - res.getDimension(R.dimen.blur_size_thin_outline), BlurMaskFilter.Blur.OUTER); - - mShadowBitmapShift = res.getDimension(R.dimen.blur_size_click_shadow); + mShadowBitmapShift = context.getResources().getDimension(R.dimen.blur_size_click_shadow); mShadowBlurMaskFilter = new BlurMaskFilter(mShadowBitmapShift, BlurMaskFilter.Blur.NORMAL); - mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } @@ -81,75 +62,6 @@ public class HolographicOutlineHelper { return sInstance; } - /** - * Applies a more expensive and accurate outline to whatever is currently drawn in a specified - * bitmap. - */ - public void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas) { - if (FeatureFlags.IS_DOGFOOD_BUILD && srcDst.getConfig() != Bitmap.Config.ALPHA_8) { - throw new RuntimeException("Outline blue is only supported on alpha bitmaps"); - } - - // We start by removing most of the alpha channel so as to ignore shadows, and - // other types of partial transparency when defining the shape of the object - byte[] pixels = new byte[srcDst.getWidth() * srcDst.getHeight()]; - ByteBuffer buffer = ByteBuffer.wrap(pixels); - buffer.rewind(); - srcDst.copyPixelsToBuffer(buffer); - - for (int i = 0; i < pixels.length; i++) { - if ((pixels[i] & 0xFF) < 188) { - pixels[i] = 0; - } - } - - buffer.rewind(); - srcDst.copyPixelsFromBuffer(buffer); - - // calculate the outer blur first - mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter); - int[] outerBlurOffset = new int[2]; - Bitmap thickOuterBlur = srcDst.extractAlpha(mBlurPaint, outerBlurOffset); - - mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter); - int[] brightOutlineOffset = new int[2]; - Bitmap brightOutline = srcDst.extractAlpha(mBlurPaint, brightOutlineOffset); - - // calculate the inner blur - srcDstCanvas.setBitmap(srcDst); - srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT); - mBlurPaint.setMaskFilter(mMediumInnerBlurMaskFilter); - int[] thickInnerBlurOffset = new int[2]; - Bitmap thickInnerBlur = srcDst.extractAlpha(mBlurPaint, thickInnerBlurOffset); - - // mask out the inner blur - srcDstCanvas.setBitmap(thickInnerBlur); - srcDstCanvas.drawBitmap(srcDst, -thickInnerBlurOffset[0], - -thickInnerBlurOffset[1], mErasePaint); - srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(), - mErasePaint); - srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1], - mErasePaint); - - // draw the inner and outer blur - srcDstCanvas.setBitmap(srcDst); - srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR); - srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1], - mDrawPaint); - srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1], - mDrawPaint); - - // draw the bright outline - srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1], - mDrawPaint); - - // cleanup - srcDstCanvas.setBitmap(null); - brightOutline.recycle(); - thickOuterBlur.recycle(); - thickInnerBlur.recycle(); - } - public Bitmap createMediumDropShadow(BubbleTextView view) { Drawable drawable = view.getIcon(); if (drawable == null) { diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java index 8ed62bcdc..5ee6a30b7 100644 --- a/src/com/android/launcher3/graphics/IconNormalizer.java +++ b/src/com/android/launcher3/graphics/IconNormalizer.java @@ -28,12 +28,15 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.AdaptiveIconDrawable; +import android.graphics.drawable.ColorDrawable; 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 com.android.launcher3.dragndrop.FolderAdaptiveIcon; + import java.io.File; import java.io.FileOutputStream; import java.nio.ByteBuffer; @@ -231,12 +234,17 @@ public class IconNormalizer { */ public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds, @Nullable Path path, @Nullable boolean[] outMaskShape) { - if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable && - mAdaptiveIconScale != SCALE_NOT_INITIALIZED) { - if (outBounds != null) { - outBounds.set(mAdaptiveIconBounds); + if (Utilities.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) { + if (mAdaptiveIconScale != SCALE_NOT_INITIALIZED) { + if (outBounds != null) { + outBounds.set(mAdaptiveIconBounds); + } + return mAdaptiveIconScale; + } + if (d instanceof FolderAdaptiveIcon) { + // Since we just want the scale, avoid heavy drawing operations + d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null); } - return mAdaptiveIconScale; } int width = d.getIntrinsicWidth(); int height = d.getIntrinsicHeight(); @@ -347,7 +355,7 @@ public class IconNormalizer { float areaScale = area / (width * height); // Use sqrt of the final ratio as the images is scaled across both width and height. float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1; - if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable && + if (Utilities.ATLEAST_OREO && d instanceof AdaptiveIconDrawable && mAdaptiveIconScale == SCALE_NOT_INITIALIZED) { mAdaptiveIconScale = scale; mAdaptiveIconBounds.set(mBounds); diff --git a/src/com/android/launcher3/graphics/IconShapeOverride.java b/src/com/android/launcher3/graphics/IconShapeOverride.java index 654fa98bc..223243b7a 100644 --- a/src/com/android/launcher3/graphics/IconShapeOverride.java +++ b/src/com/android/launcher3/graphics/IconShapeOverride.java @@ -59,7 +59,7 @@ public class IconShapeOverride { private static final int RESTART_REQUEST_CODE = 42; // the answer to everything public static boolean isSupported(Context context) { - if (!Utilities.isAtLeastO()) { + if (!Utilities.ATLEAST_OREO) { return false; } // Only supported when developer settings is enabled @@ -82,7 +82,7 @@ public class IconShapeOverride { } public static void apply(Context context) { - if (!Utilities.isAtLeastO()) { + if (!Utilities.ATLEAST_OREO) { return; } String path = getAppliedValue(context); diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java index 7c80c3098..d471af6e7 100644 --- a/src/com/android/launcher3/graphics/LauncherIcons.java +++ b/src/com/android/launcher3/graphics/LauncherIcons.java @@ -16,10 +16,12 @@ package com.android.launcher3.graphics; +import android.annotation.TargetApi; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.Intent.ShortcutIconResource; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; @@ -70,11 +72,15 @@ public class LauncherIcons { PackageManager packageManager = context.getPackageManager(); // the resource try { - Resources resources = packageManager.getResourcesForApplication(iconRes.packageName); + Resources resources = packageManager.getResourcesForApplication(iconRes.resourceName); if (resources != null) { final int id = resources.getIdentifier(iconRes.resourceName, null, null); - return createIconBitmap(resources.getDrawableForDensity( - id, LauncherAppState.getIDP(context).fillResIconDpi), context); + // do not stamp old legacy shortcuts as the app may have already forgotten about it + return createBadgedIconBitmap(resources.getDrawableForDensity( + id, LauncherAppState.getIDP(context).fillResIconDpi), + Process.myUserHandle() /* only available on primary user */, + context, + 0 /* do not apply legacy treatment */); } } catch (Exception e) { // Icon not found. @@ -90,11 +96,12 @@ public class LauncherIcons { if (iconBitmapSize == icon.getWidth() && iconBitmapSize == icon.getHeight()) { return icon; } - return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context); + return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context, 1f); } /** - * Returns a bitmap suitable for the all apps view. The icon is badged for {@param user}. + * Returns a bitmap suitable for displaying as an icon at various launcher UIs like all apps + * view or workspace. The icon is badged for {@param user}. * The bitmap is also visually normalized with other icons. */ public static Bitmap createBadgedIconBitmap( @@ -104,7 +111,7 @@ public class LauncherIcons { float scale = 1f; if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) { normalizer = IconNormalizer.getInstance(context); - if (Utilities.isAtLeastO() && iconAppTargetSdk >= Build.VERSION_CODES.O) { + if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) { boolean[] outShape = new boolean[1]; AdaptiveIconDrawable dr = (AdaptiveIconDrawable) context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate(); @@ -123,28 +130,22 @@ public class LauncherIcons { } } Bitmap bitmap = createIconBitmap(icon, context, scale); - if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() && + if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) { bitmap = ShadowGenerator.getInstance(context).recreateIcon(bitmap); } - return badgeIconForUser(bitmap, user, context); - } - /** - * Badges the provided icon with the user badge if required. - */ - public static Bitmap badgeIconForUser(Bitmap icon, UserHandle user, Context context) { if (user != null && !Process.myUserHandle().equals(user)) { - BitmapDrawable drawable = new FixedSizeBitmapDrawable(icon); + BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap); Drawable badged = context.getPackageManager().getUserBadgedIcon( drawable, user); if (badged instanceof BitmapDrawable) { return ((BitmapDrawable) badged).getBitmap(); } else { - return createIconBitmap(badged, context); + return createIconBitmap(badged, context, 1f); } } else { - return icon; + return bitmap; } } @@ -152,19 +153,20 @@ public class LauncherIcons { * Creates a normalized bitmap suitable for the all apps view. The bitmap is also visually * normalized with other icons and has enough spacing to add shadow. */ - public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context, int iconAppTargetSdk) { + public static Bitmap createScaledBitmapWithoutShadow( + Drawable icon, Context context, int iconAppTargetSdk) { RectF iconBounds = new RectF(); IconNormalizer normalizer; float scale = 1f; if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) { normalizer = IconNormalizer.getInstance(context); - if (Utilities.isAtLeastO() && iconAppTargetSdk >= Build.VERSION_CODES.O) { + if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) { boolean[] outShape = new boolean[1]; AdaptiveIconDrawable dr = (AdaptiveIconDrawable) context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate(); dr.setBounds(0, 0, 1, 1); scale = normalizer.getScale(icon, iconBounds, dr.getIconMask(), outShape); - if (Utilities.isAtLeastO() && FeatureFlags.LEGACY_ICON_TREATMENT && + if (Utilities.ATLEAST_OREO && FeatureFlags.LEGACY_ICON_TREATMENT && !outShape[0]) { Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale); if (wrappedIcon != icon) { @@ -181,21 +183,6 @@ public class LauncherIcons { return createIconBitmap(icon, context, scale); } - /** - * Adds a shadow to the provided icon. It assumes that the icon has already been scaled using - * {@link #createScaledBitmapWithoutShadow(Drawable, Context, int)} - */ - public static Bitmap addShadowToIcon(Bitmap icon, Context context) { - return ShadowGenerator.getInstance(context).recreateIcon(icon); - } - - /** - * Adds the {@param badge} on top of {@param srcTgt} using the badge dimensions. - */ - public static Bitmap badgeWithBitmap(Bitmap srcTgt, Bitmap badge, Context context) { - return badgeWithDrawable(srcTgt, new FastBitmapDrawable(badge), context); - } - public static Bitmap badgeWithDrawable(Bitmap srcTgt, Drawable badge, Context context) { int badgeSize = context.getResources().getDimensionPixelSize(R.dimen.profile_badge_size); synchronized (sCanvas) { @@ -209,26 +196,9 @@ public class LauncherIcons { } /** - * Returns a bitmap suitable for the all apps view. - */ - public static Bitmap createIconBitmap(Drawable icon, Context context) { - float scale = 1f; - if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() && - icon instanceof AdaptiveIconDrawable) { - scale = ShadowGenerator.getScaleForBounds(new RectF(0, 0, 0, 0)); - } - Bitmap bitmap = createIconBitmap(icon, context, scale); - if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() && - icon instanceof AdaptiveIconDrawable) { - bitmap = ShadowGenerator.getInstance(context).recreateIcon(bitmap); - } - return bitmap; - } - - /** * @param scale the scale to apply before drawing {@param icon} on the canvas */ - public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) { + private static Bitmap createIconBitmap(Drawable icon, Context context, float scale) { synchronized (sCanvas) { final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize; int width = iconBitmapSize; @@ -271,7 +241,7 @@ public class LauncherIcons { final int top = (textureHeight-height) / 2; sOldBounds.set(icon.getBounds()); - if (Utilities.isAtLeastO() && icon instanceof AdaptiveIconDrawable) { + if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) { int offset = Math.max((int)(ShadowGenerator.BLUR_FACTOR * iconBitmapSize), Math.min(left, top)); int size = Math.max(width, height); @@ -295,8 +265,10 @@ public class LauncherIcons { * shrink the legacy icon and set it as foreground. Use color drawable as background to * create AdaptiveIconDrawable. */ - static Drawable wrapToAdaptiveIconDrawable(Context context, Drawable drawable, float scale) { - if (!(FeatureFlags.LEGACY_ICON_TREATMENT && Utilities.isAtLeastO())) { + @TargetApi(Build.VERSION_CODES.O) + private static Drawable wrapToAdaptiveIconDrawable( + Context context, Drawable drawable, float scale) { + if (!(FeatureFlags.LEGACY_ICON_TREATMENT && Utilities.ATLEAST_OREO)) { return drawable; } @@ -307,7 +279,7 @@ public class LauncherIcons { FixedScaleDrawable fsd = ((FixedScaleDrawable) iconWrapper.getForeground()); fsd.setDrawable(drawable); fsd.setScale(scale); - return (Drawable) iconWrapper; + return iconWrapper; } } catch (Exception e) { return drawable; @@ -326,15 +298,9 @@ public class LauncherIcons { public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context, final Bitmap fallbackIcon) { - Provider<Bitmap> fallbackIconProvider = new Provider<Bitmap>() { - @Override - public Bitmap get() { - // If the shortcut is pinned but no longer has an icon in the system, - // keep the current icon instead of reverting to the default icon. - return fallbackIcon; - } - }; - return createShortcutIcon(shortcutInfo, context, true, fallbackIconProvider); + // If the shortcut is pinned but no longer has an icon in the system, + // keep the current icon instead of reverting to the default icon. + return createShortcutIcon(shortcutInfo, context, true, Provider.of(fallbackIcon)); } public static Bitmap createShortcutIcon(ShortcutInfoCompat shortcutInfo, Context context, @@ -360,8 +326,9 @@ public class LauncherIcons { if (!badged) { return unbadgedBitmap; } - unbadgedBitmap = LauncherIcons.addShadowToIcon(unbadgedBitmap, context); - return badgeWithBitmap(unbadgedBitmap, getShortcutInfoBadge(shortcutInfo, cache), context); + unbadgedBitmap = ShadowGenerator.getInstance(context).recreateIcon(unbadgedBitmap); + return badgeWithDrawable(unbadgedBitmap, + new FastBitmapDrawable(getShortcutInfoBadge(shortcutInfo, cache)), context); } public static Bitmap getShortcutInfoBadge(ShortcutInfoCompat shortcutInfo, IconCache cache) { diff --git a/src/com/android/launcher3/graphics/ShadowDrawable.java b/src/com/android/launcher3/graphics/ShadowDrawable.java index ffcedb26a..b40bf7828 100644 --- a/src/com/android/launcher3/graphics/ShadowDrawable.java +++ b/src/com/android/launcher3/graphics/ShadowDrawable.java @@ -146,7 +146,7 @@ public class ShadowDrawable extends Drawable { d.draw(canvas); } - if (Utilities.isAtLeastO()) { + if (Utilities.ATLEAST_OREO) { bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false); } mState.mLastDrawnBitmap = bitmap; diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java index ebb69c43b..81333b1a2 100644 --- a/src/com/android/launcher3/logging/LoggerUtils.java +++ b/src/com/android/launcher3/logging/LoggerUtils.java @@ -105,13 +105,13 @@ public class LoggerUtils { private static String getItemStr(Target t) { String typeStr = getFieldName(t.itemType, ItemType.class); if (t.packageNameHash != 0) { - typeStr += ", packageHash=" + t.packageNameHash; + typeStr += ", packageHash=" + t.packageNameHash + ", predictiveRank=" + t.predictedRank; } if (t.componentHash != 0) { - typeStr += ", componentHash=" + t.componentHash; + typeStr += ", componentHash=" + t.componentHash + ", predictiveRank=" + t.predictedRank; } if (t.intentHash != 0) { - typeStr += ", intentHash=" + t.intentHash; + typeStr += ", intentHash=" + t.intentHash + ", predictiveRank=" + t.predictedRank; } return typeStr + ", grid(" + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY + "), pageIdx=" + t.pageIndex; @@ -125,9 +125,11 @@ public class LoggerUtils { public static Target newItemTarget(ItemInfo info) { Target t = newTarget(Target.Type.ITEM); + switch (info.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: t.itemType = ItemType.APP_ICON; + t.predictedRank = -100; // Never assigned break; case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: t.itemType = ItemType.SHORTCUT; diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index 8de0de053..d9b1a3f9e 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -726,7 +726,7 @@ public class GridSizeMigrationTask { mContext).getLauncherAppWidgetInfo(widgetId); Point spans = null; if (pInfo != null) { - spans = pInfo.getMinSpans(mIdp, mContext); + spans = pInfo.getMinSpans(); } if (spans != null) { entry.minSpanX = spans.x > 0 ? spans.x : entry.spanX; diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index e1b208a05..5386fb4a5 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -66,6 +66,7 @@ import com.android.launcher3.util.ManagedProfileHeuristic; import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Provider; +import com.android.launcher3.util.TraceHelper; import java.util.ArrayList; import java.util.Collections; @@ -85,7 +86,6 @@ import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_I * - deep shortcuts within apps */ public class LoaderTask implements Runnable { - private static final boolean DEBUG_LOADERS = false; private static final String TAG = "LoaderTask"; private final LauncherAppState mApp; @@ -142,73 +142,64 @@ public class LoaderTask implements Runnable { } } + TraceHelper.beginSection(TAG); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { - long now = 0; - if (DEBUG_LOADERS) Log.d(TAG, "step 1.1: loading workspace"); + TraceHelper.partitionSection(TAG, "step 1.1: loading workspace"); loadWorkspace(); verifyNotStopped(); - if (DEBUG_LOADERS) Log.d(TAG, "step 1.2: bind workspace workspace"); + TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace"); mResults.bindWorkspace(); // Take a break - if (DEBUG_LOADERS) { - Log.d(TAG, "step 1 completed, wait for idle"); - now = SystemClock.uptimeMillis(); - } + TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle"); waitForIdle(); - if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms"); verifyNotStopped(); // second step - if (DEBUG_LOADERS) Log.d(TAG, "step 2.1: loading all apps"); + TraceHelper.partitionSection(TAG, "step 2.1: loading all apps"); loadAllApps(); - if (DEBUG_LOADERS) Log.d(TAG, "step 2.2: Binding all apps"); + TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps"); verifyNotStopped(); mResults.bindAllApps(); verifyNotStopped(); - if (DEBUG_LOADERS) Log.d(TAG, "step 2.3: Update icon cache"); + TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache"); updateIconCache(); // Take a break - if (DEBUG_LOADERS) { - Log.d(TAG, "step 2 completed, wait for idle"); - now = SystemClock.uptimeMillis(); - } + TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle"); waitForIdle(); - if (DEBUG_LOADERS) Log.d(TAG, "Waited " + (SystemClock.uptimeMillis() - now) + "ms"); verifyNotStopped(); // third step - if (DEBUG_LOADERS) Log.d(TAG, "step 3.1: loading deep shortcuts"); + TraceHelper.partitionSection(TAG, "step 3.1: loading deep shortcuts"); loadDeepShortcuts(); verifyNotStopped(); - if (DEBUG_LOADERS) Log.d(TAG, "step 3.2: bind deep shortcuts"); + TraceHelper.partitionSection(TAG, "step 3.2: bind deep shortcuts"); mResults.bindDeepShortcuts(); // Take a break - if (DEBUG_LOADERS) Log.d(TAG, "step 3 completed, wait for idle"); + TraceHelper.partitionSection(TAG, "step 3 completed, wait for idle"); waitForIdle(); verifyNotStopped(); // fourth step - if (DEBUG_LOADERS) Log.d(TAG, "step 4.1: loading widgets"); + TraceHelper.partitionSection(TAG, "step 4.1: loading widgets"); mBgDataModel.widgetsModel.update(mApp, null); verifyNotStopped(); - if (DEBUG_LOADERS) Log.d(TAG, "step 4.2: Binding widgets"); + TraceHelper.partitionSection(TAG, "step 4.2: Binding widgets"); mResults.bindWidgets(); transaction.commit(); } catch (CancellationException e) { // Loader stopped, ignore - if (DEBUG_LOADERS) { - Log.d(TAG, "Loader cancelled", e); - } + TraceHelper.partitionSection(TAG, "Cancelled"); } + TraceHelper.endSection(TAG); } public synchronized void stopLocked() { @@ -217,10 +208,6 @@ public class LoaderTask implements Runnable { } private void loadWorkspace() { - if (LauncherAppState.PROFILE_STARTUP) { - Trace.beginSection("Loading Workspace"); - } - final Context context = mApp.getContext(); final ContentResolver contentResolver = context.getContentResolver(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); @@ -766,9 +753,6 @@ public class LoaderTask implements Runnable { LauncherModel.updateWorkspaceScreenOrder(context, mBgDataModel.workspaceScreens); } } - if (LauncherAppState.PROFILE_STARTUP) { - Trace.endSection(); - } } private void updateIconCache() { @@ -793,21 +777,13 @@ public class LoaderTask implements Runnable { } private void loadAllApps() { - final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - final List<UserHandle> profiles = mUserManager.getUserProfiles(); // Clear the list of apps mBgAllAppsList.clear(); for (UserHandle user : profiles) { // Query for the set of apps - final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user); - if (DEBUG_LOADERS) { - Log.d(TAG, "getActivityList took " - + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user); - Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user); - } // Fail if we don't have any apps // TODO: Fix this. Only fail for the current user. if (apps == null || apps.isEmpty()) { @@ -834,10 +810,6 @@ public class LoaderTask implements Runnable { } mBgAllAppsList.added = new ArrayList<>(); - if (DEBUG_LOADERS) { - Log.d(TAG, "All apps loaded in in " - + (SystemClock.uptimeMillis() - loadTime) + "ms"); - } } private void loadDeepShortcuts() { diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 13962a259..78ecbc621 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -101,7 +101,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { appsList.addPackage(context, packages[i], mUser); // Automatically add homescreen icon for work profile apps for below O device. - if (!Utilities.isAtLeastO() && !Process.myUserHandle().equals(mUser)) { + if (!Utilities.ATLEAST_OREO && !Process.myUserHandle().equals(mUser)) { SessionCommitReceiver.queueAppIconAddition(context, packages[i], mUser); } } @@ -178,6 +178,9 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) { final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>(); final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<>(); + + // For system apps, package manager send OP_UPDATE when an app is enabled. + final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE; synchronized (dataModel) { for (ItemInfo info : dataModel.itemsIdMap) { if (info instanceof ShortcutInfo && mUser.equals(info.user)) { @@ -206,9 +209,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { } } - // For system apps, package manager send OP_UPDATE when an - // app is enabled. - if (si.isPromise() && (mOp == OP_ADD || mOp == OP_UPDATE)) { + if (si.isPromise() && isNewApkAvailable) { if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINSTALL_ICON)) { // Auto install icon LauncherAppsCompat launcherApps @@ -231,10 +232,13 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { continue; } } + } else { + si.status = ShortcutInfo.DEFAULT; + infoUpdated = true; } } - if ((mOp == OP_ADD || mOp == OP_UPDATE) && + if (isNewApkAvailable && si.itemType == Favorites.ITEM_TYPE_APPLICATION) { iconCache.getTitleAndIcon(si, si.usingLowResIcon); infoUpdated = true; @@ -253,7 +257,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { if (infoUpdated) { getModelWriter().updateItemInDatabase(si); } - } else if (info instanceof LauncherAppWidgetInfo && mOp == OP_ADD) { + } else if (info instanceof LauncherAppWidgetInfo && isNewApkAvailable) { LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info; if (mUser.equals(widgetInfo.user) && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) @@ -342,8 +346,9 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { callbacks.notifyWidgetProvidersChanged(); } }); - } else if (Utilities.isAtLeastO() && mOp == OP_ADD) { - // Load widgets for the new package. + } else if (Utilities.ATLEAST_OREO && mOp == OP_ADD) { + // Load widgets for the new package. Changes due to app updates are handled through + // AppWidgetHost events, this is just to initialize the long-press options. for (int i = 0; i < N; i++) { dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser)); } diff --git a/src/com/android/launcher3/notification/NotificationGroup.java b/src/com/android/launcher3/notification/NotificationGroup.java new file mode 100644 index 000000000..bce211754 --- /dev/null +++ b/src/com/android/launcher3/notification/NotificationGroup.java @@ -0,0 +1,52 @@ +/* + * 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.notification; + +import java.util.HashSet; +import java.util.Set; + +/** + * Contains data related to a group of notifications, like the group summary key and the child keys. + */ +public class NotificationGroup { + private String mGroupSummaryKey; + private Set<String> mChildKeys; + + public NotificationGroup() { + mChildKeys = new HashSet<>(); + } + + public void setGroupSummaryKey(String groupSummaryKey) { + mGroupSummaryKey = groupSummaryKey; + } + + public String getGroupSummaryKey() { + return mGroupSummaryKey; + } + + public void addChildKey(String childKey) { + mChildKeys.add(childKey); + } + + public void removeChildKey(String childKey) { + mChildKeys.remove(childKey); + } + + public boolean isEmpty() { + return mChildKeys.isEmpty(); + } +} diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java index 1b7c87b22..6e36f4f51 100644 --- a/src/com/android/launcher3/notification/NotificationInfo.java +++ b/src/com/android/launcher3/notification/NotificationInfo.java @@ -94,6 +94,9 @@ public class NotificationInfo implements View.OnClickListener { @Override public void onClick(View view) { + if (intent == null) { + return; + } final Launcher launcher = Launcher.getLauncher(view.getContext()); Bundle activityOptions = ActivityOptions.makeClipRevealAnimation( view, 0, 0, view.getWidth(), view.getHeight()).toBundle(); diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java index 91266263f..7b70df77e 100644 --- a/src/com/android/launcher3/notification/NotificationListener.java +++ b/src/com/android/launcher3/notification/NotificationListener.java @@ -38,7 +38,9 @@ import com.android.launcher3.util.SettingsObserver; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING; @@ -66,6 +68,8 @@ public class NotificationListener extends NotificationListenerService { private final Handler mWorkerHandler; private final Handler mUiHandler; private final Ranking mTempRanking = new Ranking(); + /** Maps groupKey's to the corresponding group of notifications. */ + private final Map<String, NotificationGroup> mNotificationGroupMap = new HashMap<>(); private SettingsObserver mNotificationBadgingObserver; @@ -227,6 +231,15 @@ public class NotificationListener extends NotificationListenerService { NotificationKeyData.fromNotification(sbn)); mWorkerHandler.obtainMessage(MSG_NOTIFICATION_REMOVED, packageUserKeyAndNotificationKey) .sendToTarget(); + + NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey()); + if (notificationGroup != null) { + notificationGroup.removeChildKey(sbn.getKey()); + if (notificationGroup.isEmpty()) { + cancelNotification(notificationGroup.getGroupSummaryKey()); + mNotificationGroupMap.remove(sbn.getGroupKey()); + } + } } /** This makes a potentially expensive binder call and should be run on a background thread. */ @@ -264,18 +277,34 @@ public class NotificationListener extends NotificationListenerService { } private boolean shouldBeFilteredOut(StatusBarNotification sbn) { + Notification notification = sbn.getNotification(); + + boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0; + if (sbn.isGroup()) { + // Maintain group info so we can cancel the summary when the last child is canceled. + NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey()); + if (notificationGroup == null) { + notificationGroup = new NotificationGroup(); + mNotificationGroupMap.put(sbn.getGroupKey(), notificationGroup); + } + if (isGroupHeader) { + notificationGroup.setGroupSummaryKey(sbn.getKey()); + } else { + notificationGroup.addChildKey(sbn.getKey()); + } + } + getCurrentRanking().getRanking(sbn.getKey(), mTempRanking); if (!mTempRanking.canShowBadge()) { return true; } - Notification notification = sbn.getNotification(); if (mTempRanking.getChannel().getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) { // Special filtering for the default, legacy "Miscellaneous" channel. if ((notification.flags & Notification.FLAG_ONGOING_EVENT) != 0) { return true; } } - boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0; + CharSequence title = notification.extras.getCharSequence(Notification.EXTRA_TITLE); CharSequence text = notification.extras.getCharSequence(Notification.EXTRA_TEXT); boolean missingTitleAndText = TextUtils.isEmpty(title) && TextUtils.isEmpty(text); diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java index 47c2ffb38..d6ef5b4c8 100644 --- a/src/com/android/launcher3/pageindicators/PageIndicator.java +++ b/src/com/android/launcher3/pageindicators/PageIndicator.java @@ -20,8 +20,6 @@ import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.FrameLayout; -import com.android.launcher3.dynamicui.ExtractedColors; - /** * Base class for a page indicator. */ @@ -74,8 +72,6 @@ public abstract class PageIndicator extends FrameLayout { public void setShouldAutoHide(boolean shouldAutoHide) {} - public void updateColor(ExtractedColors extractedColors) {} - @Override protected boolean verifyDrawable(Drawable who) { return super.verifyDrawable(who) || who == getCaretDrawable(); diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java index 682d5a967..911be93fc 100644 --- a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java +++ b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java @@ -48,7 +48,6 @@ public class PageIndicatorCaretLandscape extends PageIndicator { setCaretDrawable(caretDrawable); Launcher l = Launcher.getLauncher(context); - setOnTouchListener(l.getHapticFeedbackTouchListener()); setOnClickListener(l); setOnFocusChangeListener(l.mFocusHandler); } diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java index 29834d764..5eedd92fd 100644 --- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java +++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java @@ -11,9 +11,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.os.Handler; import android.os.Looper; -import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; -import android.util.Log; import android.util.Property; import android.view.ViewConfiguration; import android.widget.ImageView; @@ -21,8 +19,6 @@ import android.widget.ImageView; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.dynamicui.ExtractedColors; import com.android.launcher3.dynamicui.WallpaperColorInfo; /** @@ -31,9 +27,6 @@ import com.android.launcher3.dynamicui.WallpaperColorInfo; * The fraction is 1 / number of pages and the position is based on the progress of the page scroll. */ public class PageIndicatorLineCaret extends PageIndicator { - private static final String TAG = "PageIndicatorLine"; - - private static final int[] sTempCoords = new int[2]; private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration(); private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay(); @@ -141,7 +134,6 @@ public class PageIndicatorLineCaret extends PageIndicator { super.onFinishInflate(); mAllAppsHandle = (ImageView) findViewById(R.id.all_apps_handle); mAllAppsHandle.setImageDrawable(getCaretDrawable()); - mAllAppsHandle.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener()); mAllAppsHandle.setOnClickListener(mLauncher); mAllAppsHandle.setOnFocusChangeListener(mLauncher.mFocusHandler); mLauncher.setAllAppsButton(mAllAppsHandle); @@ -219,32 +211,6 @@ public class PageIndicatorLineCaret extends PageIndicator { } } - /** - * The line's color will be: - * - mostly opaque white if the hotseat is white (ignoring alpha) - * - mostly opaque black if the hotseat is black (ignoring alpha) - */ - public void updateColor(ExtractedColors extractedColors) { - if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) { - return; - } - int originalLineAlpha = mLinePaint.getAlpha(); - int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX); - if (color != Color.TRANSPARENT) { - color = ColorUtils.setAlphaComponent(color, 255); - if (color == Color.BLACK) { - mActiveAlpha = BLACK_ALPHA; - } else if (color == Color.WHITE) { - mActiveAlpha = WHITE_ALPHA; - } else { - Log.e(TAG, "Setting workspace page indicators to an unsupported color: #" - + Integer.toHexString(color)); - } - mLinePaint.setColor(color); - mLinePaint.setAlpha(originalLineAlpha); - } - } - private void animateLineToAlpha(int alpha) { if (alpha == mToAlpha) { // Ignore the new animation if it is going to the same alpha as the current animation. diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 8441598cf..5c49b4bdf 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -16,6 +16,11 @@ package com.android.launcher3.popup; +import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; +import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Target; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -66,6 +71,7 @@ import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.graphics.TriangleShape; +import com.android.launcher3.logging.LoggerUtils; import com.android.launcher3.notification.NotificationItemView; import com.android.launcher3.notification.NotificationKeyData; import com.android.launcher3.shortcuts.DeepShortcutManager; @@ -81,11 +87,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; -import static com.android.launcher3.userevent.nano.LauncherLogProto.Target; - /** * A container for shortcuts to deep links within apps. */ @@ -593,11 +594,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra return arrowView; } - @Override - public View getExtendedTouchView() { - return mOriginalIcon; - } - /** * Determines when the deferred drag should be started. * @@ -797,21 +793,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra } @Override - public boolean supportsAppInfoDropTarget() { - return true; - } - - @Override - public boolean supportsDeleteDropTarget() { - return false; - } - - @Override - public float getIntrinsicIconScaleFactor() { - return 1f; - } - - @Override public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete, boolean success) { if (!success) { @@ -950,7 +931,25 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra } @Override - public int getLogContainerType() { - return ContainerType.DEEPSHORTCUTS; + public void logActionCommand(int command) { + mLauncher.getUserEventDispatcher().logActionCommand( + command, mOriginalIcon, ContainerType.DEEPSHORTCUTS); + } + + @Override + public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + DragLayer dl = mLauncher.getDragLayer(); + if (!dl.isEventOverView(this, ev)) { + mLauncher.getUserEventDispatcher().logActionTapOutside( + LoggerUtils.newContainerTarget(ContainerType.DEEPSHORTCUTS)); + close(true); + + // We let touches on the original icon go through so that users can launch + // the app with one tap if they don't find a shortcut they want. + return mOriginalIcon == null || !dl.isEventOverView(mOriginalIcon, ev); + } + } + return false; } } diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java index d26f9f646..65acaa973 100644 --- a/src/com/android/launcher3/qsb/QsbContainerView.java +++ b/src/com/android/launcher3/qsb/QsbContainerView.java @@ -36,6 +36,7 @@ import android.widget.FrameLayout; import com.android.launcher3.AppWidgetResizeFrame; import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -79,10 +80,15 @@ public class QsbContainerView extends FrameLayout { private AppWidgetProviderInfo mWidgetInfo; private QsbWidgetHostView mQsb; + // We need to store the orientation here, due to a bug (b/64916689) that results in widgets + // being inflated in the wrong orientation. + private int mOrientation; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mQsbWidgetHost = new QsbWidgetHost(getActivity()); + mOrientation = getContext().getResources().getConfiguration().orientation; } private FrameLayout mWrapper; @@ -193,7 +199,7 @@ public class QsbContainerView extends FrameLayout { @Override public void onResume() { super.onResume(); - if (mQsb != null && mQsb.isReinflateRequired()) { + if (mQsb != null && mQsb.isReinflateRequired(mOrientation)) { rebindFragment(); } } diff --git a/src/com/android/launcher3/qsb/QsbWidgetHostView.java b/src/com/android/launcher3/qsb/QsbWidgetHostView.java index 8b6fa1651..a8a41f664 100644 --- a/src/com/android/launcher3/qsb/QsbWidgetHostView.java +++ b/src/com/android/launcher3/qsb/QsbWidgetHostView.java @@ -47,9 +47,9 @@ public class QsbWidgetHostView extends AppWidgetHostView { } - public boolean isReinflateRequired() { + public boolean isReinflateRequired(int orientation) { // Re-inflate is required if the orientation has changed since last inflation. - return mPreviousOrientation != getResources().getConfiguration().orientation; + return mPreviousOrientation != orientation; } diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java index e9d2b50ea..cfb9258dd 100644 --- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java +++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java @@ -26,7 +26,6 @@ import android.view.View; import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; import com.android.launcher3.graphics.DragPreviewProvider; -import com.android.launcher3.graphics.HolographicOutlineHelper; /** * Extension of {@link DragPreviewProvider} which generates bitmaps scaled to the default icon size. @@ -40,35 +39,17 @@ public class ShortcutDragPreviewProvider extends DragPreviewProvider { mPositionShift = shift; } - @Override - public Bitmap createDragOutline(Canvas canvas) { - Bitmap b = drawScaledPreview(canvas, Bitmap.Config.ALPHA_8); - - HolographicOutlineHelper.getInstance(mView.getContext()) - .applyExpensiveOutlineWithBlur(b, canvas); - canvas.setBitmap(null); - return b; - } - - @Override - public Bitmap createDragBitmap(Canvas canvas) { - Bitmap b = drawScaledPreview(canvas, Bitmap.Config.ARGB_8888); - canvas.setBitmap(null); - return b; - } - - private Bitmap drawScaledPreview(Canvas canvas, Bitmap.Config config) { + public Bitmap createDragBitmap() { Drawable d = mView.getBackground(); Rect bounds = getDrawableBounds(d); int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx; - final Bitmap b = Bitmap.createBitmap( size + blurSizeOutline, size + blurSizeOutline, - config); + Bitmap.Config.ARGB_8888); - canvas.setBitmap(b); + Canvas canvas = new Canvas(b); canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.translate(blurSizeOutline / 2, blurSizeOutline / 2); canvas.scale(((float) size) / bounds.width(), ((float) size) / bounds.height(), 0, 0); diff --git a/src/com/android/launcher3/testing/DummyWidget.java b/src/com/android/launcher3/testing/DummyWidget.java deleted file mode 100644 index df887ac1f..000000000 --- a/src/com/android/launcher3/testing/DummyWidget.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.android.launcher3.testing; - -import android.appwidget.AppWidgetProviderInfo; - -import com.android.launcher3.CustomAppWidget; -import com.android.launcher3.R; - -public class DummyWidget implements CustomAppWidget { - @Override - public String getLabel() { - return "Dumb Launcher Widget"; - } - - @Override - public int getPreviewImage() { - return 0; - } - - @Override - public int getIcon() { - return 0; - } - - @Override - public int getWidgetLayout() { - return R.layout.zzz_dummy_widget; - } - - @Override - public int getSpanX() { - return 2; - } - - @Override - public int getSpanY() { - return 2; - } - - @Override - public int getMinSpanX() { - return 1; - } - - @Override - public int getMinSpanY() { - return 1; - } - - @Override - public int getResizeMode() { - return AppWidgetProviderInfo.RESIZE_BOTH; - } -} diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java index 355963bfe..a1a4d7555 100644 --- a/src/com/android/launcher3/testing/LauncherExtension.java +++ b/src/com/android/launcher3/testing/LauncherExtension.java @@ -7,13 +7,10 @@ import android.view.Menu; import com.android.launcher3.AppInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherCallbacks; -import com.android.launcher3.util.ComponentKey; -import com.android.launcher3.util.ComponentKeyMapper; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.List; /** * This class represents a very trivial LauncherExtension. It primarily serves as a simple @@ -150,12 +147,6 @@ public class LauncherExtension extends Launcher { } @Override - public List<ComponentKeyMapper<AppInfo>> getPredictedApps() { - // To debug app predictions, enable AlphabeticalAppsList#DEBUG_PREDICTIONS - return new ArrayList<>(); - } - - @Override public void onAttachedToWindow() { } diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java index 091dd84bc..009aee775 100644 --- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java +++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java @@ -67,7 +67,7 @@ public class ManagedProfileHeuristic { return; } - if (Utilities.isAtLeastO() && !SessionCommitReceiver.isEnabled(context)) { + if (Utilities.ATLEAST_OREO && !SessionCommitReceiver.isEnabled(context)) { // Just mark the folder id preference to avoid new folder creation later. ufi.prefs.edit().putLong(ufi.folderIdKey, ItemInfo.NO_ID).apply(); return; diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java index d7a2625e9..edbf05a7c 100644 --- a/src/com/android/launcher3/util/SystemUiController.java +++ b/src/com/android/launcher3/util/SystemUiController.java @@ -59,7 +59,7 @@ public class SystemUiController { // Apply the state flags in priority order int newFlags = oldFlags; for (int stateFlag : mStates) { - if (Utilities.isAtLeastO()) { + if (Utilities.ATLEAST_OREO) { if ((stateFlag & FLAG_LIGHT_NAV) != 0) { newFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } else if ((stateFlag & FLAG_DARK_NAV) != 0) { diff --git a/src/com/android/launcher3/util/TestingUtils.java b/src/com/android/launcher3/util/TestingUtils.java index a7cc42b5f..d927dc335 100644 --- a/src/com/android/launcher3/util/TestingUtils.java +++ b/src/com/android/launcher3/util/TestingUtils.java @@ -3,18 +3,14 @@ package com.android.launcher3.util; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; -import com.android.launcher3.CustomAppWidget; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import java.util.HashMap; - public class TestingUtils { public static final String MEMORY_TRACKER = "com.android.launcher3.testing.MemoryTracker"; @@ -23,9 +19,6 @@ public class TestingUtils { public static final boolean MEMORY_DUMP_ENABLED = false; public static final String SHOW_WEIGHT_WATCHER = "debug.show_mem"; - public static final boolean ENABLE_CUSTOM_WIDGET_TEST = false; - public static final String DUMMY_WIDGET = "com.android.launcher3.testing.DummyWidget"; - public static void startTrackingMemory(Context context) { if (MEMORY_DUMP_ENABLED) { context.startService(new Intent() @@ -55,16 +48,4 @@ public class TestingUtils { launcher.mWeightWatcher = watcher; } } - - public static void addDummyWidget(HashMap<String, CustomAppWidget> set) { - if (ENABLE_CUSTOM_WIDGET_TEST) { - try { - Class<?> clazz = Class.forName(DUMMY_WIDGET); - CustomAppWidget widget = (CustomAppWidget) clazz.newInstance(); - set.put(widget.getClass().getName(), widget); - } catch (Exception e) { - Log.e("TestingUtils", "Error adding dummy widget", e); - } - } - } } diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java new file mode 100644 index 000000000..5b66fcda6 --- /dev/null +++ b/src/com/android/launcher3/util/TraceHelper.java @@ -0,0 +1,90 @@ +/* + * 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.os.SystemClock; +import android.os.Trace; +import android.util.ArrayMap; +import android.util.Log; +import android.util.MutableLong; + +import com.android.launcher3.config.FeatureFlags; + +/** + * A wrapper around {@link Trace} to allow easier proguarding for production builds. + * + * To enable any tracing log, execute the following command: + * $ adb shell setprop log.tag.TAGNAME VERBOSE + */ +public class TraceHelper { + + private static final boolean ENABLED = FeatureFlags.IS_DOGFOOD_BUILD; + + private static final boolean SYSTEM_TRACE = true; + private static final ArrayMap<String, MutableLong> sUpTimes = + ENABLED ? new ArrayMap<String, MutableLong>() : null; + + public static void beginSection(String sectionName) { + if (ENABLED) { + MutableLong time = sUpTimes.get(sectionName); + if (time == null) { + time = new MutableLong(Log.isLoggable(sectionName, Log.VERBOSE) ? 0 : -1); + sUpTimes.put(sectionName, time); + } + if (time.value >= 0) { + if (SYSTEM_TRACE) { + Trace.beginSection(sectionName); + } + time.value = SystemClock.uptimeMillis(); + } + } + } + + public static void partitionSection(String sectionName, String partition) { + if (ENABLED) { + MutableLong time = sUpTimes.get(sectionName); + if (time.value >= 0) { + + if (SYSTEM_TRACE) { + Trace.endSection(); + Trace.beginSection(sectionName); + } + + long now = SystemClock.uptimeMillis(); + Log.d(sectionName, partition + " : " + (now - time.value)); + time.value = now; + } + } + } + + public static void endSection(String sectionName) { + if (ENABLED) { + endSection(sectionName, "End"); + } + } + + public static void endSection(String sectionName, String msg) { + if (ENABLED) { + MutableLong time = sUpTimes.get(sectionName); + if (time.value >= 0) { + if (SYSTEM_TRACE) { + Trace.endSection(); + } + Log.d(sectionName, msg + " : " + (SystemClock.uptimeMillis() - time.value)); + } + } + } +} diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java new file mode 100644 index 000000000..27140a113 --- /dev/null +++ b/src/com/android/launcher3/util/UiThreadHelper.java @@ -0,0 +1,76 @@ +/* + * 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.Context; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.view.inputmethod.InputMethodManager; + +/** + * Utility class for offloading some class from UI thread + */ +public class UiThreadHelper { + + private static HandlerThread sHandlerThread; + private static Handler sHandler; + + private static final int MSG_HIDE_KEYBOARD = 1; + + public static Looper getBackgroundLooper() { + if (sHandlerThread == null) { + sHandlerThread = + new HandlerThread("UiThreadHelper", Process.THREAD_PRIORITY_FOREGROUND); + sHandlerThread.start(); + } + return sHandlerThread.getLooper(); + } + + private static Handler getHandler(Context context) { + if (sHandler == null) { + sHandler = new Handler(getBackgroundLooper(), + new UiCallbacks(context.getApplicationContext())); + } + return sHandler; + } + + public static void hideKeyboardAsync(Context context, IBinder token) { + Message.obtain(getHandler(context), MSG_HIDE_KEYBOARD, token).sendToTarget(); + } + + private static class UiCallbacks implements Handler.Callback { + + private final InputMethodManager mIMM; + + UiCallbacks(Context context) { + mIMM = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + } + + @Override + public boolean handleMessage(Message message) { + switch (message.what) { + case MSG_HIDE_KEYBOARD: + mIMM.hideSoftInputFromWindow((IBinder) message.obj, 0); + return true; + } + return false; + } + } +} diff --git a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java index f99efcec9..ec494f181 100644 --- a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java +++ b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java @@ -1,9 +1,15 @@ package com.android.launcher3.util; import android.app.WallpaperManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.os.SystemClock; import android.util.Log; -import android.view.Choreographer; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; @@ -13,60 +19,30 @@ import com.android.launcher3.Workspace; /** * Utility class to handle wallpaper scrolling along with workspace. */ -public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback { +public class WallpaperOffsetInterpolator extends BroadcastReceiver { + + private static final int[] sTempInt = new int[2]; private static final String TAG = "WPOffsetInterpolator"; private static final int ANIMATION_DURATION = 250; // Don't use all the wallpaper for parallax until you have at least this many pages private static final int MIN_PARALLAX_PAGE_SPAN = 4; - private final Choreographer mChoreographer; - private final Interpolator mInterpolator; - private final WallpaperManager mWallpaperManager; private final Workspace mWorkspace; private final boolean mIsRtl; + private final Handler mHandler; + private boolean mRegistered = false; private IBinder mWindowToken; private boolean mWallpaperIsLiveWallpaper; - private float mLastSetWallpaperOffsetSteps = 0; - private float mFinalOffset = 0.0f; - private float mCurrentOffset = 0.5f; // to force an initial update - private boolean mWaitingForUpdate; private boolean mLockedToDefaultPage; - - private boolean mAnimating; - private long mAnimationStartTime; - private float mAnimationStartOffset; - int mNumScreens; - int mNumPagesForWallpaperParallax; + private int mNumScreens; public WallpaperOffsetInterpolator(Workspace workspace) { - mChoreographer = Choreographer.getInstance(); - mInterpolator = new DecelerateInterpolator(1.5f); - mWorkspace = workspace; - mWallpaperManager = WallpaperManager.getInstance(workspace.getContext()); mIsRtl = Utilities.isRtl(workspace.getResources()); - } - - @Override - public void doFrame(long frameTimeNanos) { - updateOffset(false); - } - - private void updateOffset(boolean force) { - if (mWaitingForUpdate || force) { - mWaitingForUpdate = false; - if (computeScrollOffset() && mWindowToken != null) { - try { - mWallpaperManager.setWallpaperOffsets(mWindowToken, getCurrX(), 0.5f); - setWallpaperOffsetSteps(); - } catch (IllegalArgumentException e) { - Log.e(TAG, "Error updating wallpaper offset: " + e); - } - } - } + mHandler = new OffsetHandler(workspace.getContext()); } /** @@ -80,46 +56,25 @@ public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback return mLockedToDefaultPage; } - public boolean computeScrollOffset() { - final float oldOffset = mCurrentOffset; - if (mAnimating) { - long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime; - float t0 = durationSinceAnimation / (float) ANIMATION_DURATION; - float t1 = mInterpolator.getInterpolation(t0); - mCurrentOffset = mAnimationStartOffset + - (mFinalOffset - mAnimationStartOffset) * t1; - mAnimating = durationSinceAnimation < ANIMATION_DURATION; - } else { - mCurrentOffset = mFinalOffset; - } - - if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) { - scheduleUpdate(); - } - if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) { - return true; - } - return false; - } - /** + * Computes the wallpaper offset as an int ratio (out[0] / out[1]) + * * TODO: do different behavior if it's a live wallpaper? */ - public float wallpaperOffsetForScroll(int scroll) { + private void wallpaperOffsetForScroll(int scroll, int numScrollingPages, final int[] out) { + out[1] = 1; + // To match the default wallpaper behavior in the system, we default to either the left // or right edge on initialization - int numScrollingPages = getNumScreensExcludingEmpty(); if (mLockedToDefaultPage || numScrollingPages <= 1) { - return mIsRtl ? 1f : 0f; + out[0] = mIsRtl ? 1 : 0; + return; } // Distribute the wallpaper parallax over a minimum of MIN_PARALLAX_PAGE_SPAN workspace // screens, not including the custom screen, and empty screens (if > MIN_PARALLAX_PAGE_SPAN) - if (mWallpaperIsLiveWallpaper) { - mNumPagesForWallpaperParallax = numScrollingPages; - } else { - mNumPagesForWallpaperParallax = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages); - } + int numPagesForWallpaperParallax = mWallpaperIsLiveWallpaper ? numScrollingPages : + Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages); // Offset by the custom screen int leftPageIndex; @@ -136,106 +91,184 @@ public class WallpaperOffsetInterpolator implements Choreographer.FrameCallback int leftPageScrollX = mWorkspace.getScrollForPage(leftPageIndex); int rightPageScrollX = mWorkspace.getScrollForPage(rightPageIndex); int scrollRange = rightPageScrollX - leftPageScrollX; - if (scrollRange == 0) { - return 0f; + if (scrollRange <= 0) { + out[0] = 0; + return; } // Sometimes the left parameter of the pages is animated during a layout transition; // this parameter offsets it to keep the wallpaper from animating as well int adjustedScroll = scroll - leftPageScrollX - mWorkspace.getLayoutTransitionOffsetForPage(0); - float offset = Utilities.boundToRange((float) adjustedScroll / scrollRange, 0f, 1f); + adjustedScroll = Utilities.boundToRange(adjustedScroll, 0, scrollRange); + out[1] = (numPagesForWallpaperParallax - 1) * scrollRange; // The offset is now distributed 0..1 between the left and right pages that we care about, // so we just map that between the pages that we are using for parallax - float rtlOffset = 0; + int rtlOffset = 0; if (mIsRtl) { // In RTL, the pages are right aligned, so adjust the offset from the end - rtlOffset = (float) ((mNumPagesForWallpaperParallax - 1) - (numScrollingPages - 1)) / - (mNumPagesForWallpaperParallax - 1); + rtlOffset = out[1] - (numScrollingPages - 1) * scrollRange; } - return rtlOffset + offset * - ((float) (numScrollingPages - 1) / (mNumPagesForWallpaperParallax - 1)); + out[0] = rtlOffset + adjustedScroll * (numScrollingPages - 1); } - private float wallpaperOffsetForCurrentScroll() { - return wallpaperOffsetForScroll(mWorkspace.getScrollX()); + public float wallpaperOffsetForScroll(int scroll) { + wallpaperOffsetForScroll(scroll, getNumScreensExcludingEmpty(), sTempInt); + return ((float) sTempInt[0]) / sTempInt[1]; } - private int numEmptyScreensToIgnore() { + private int getNumScreensExcludingEmpty() { int numScrollingPages = mWorkspace.getChildCount(); if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && mWorkspace.hasExtraEmptyScreen()) { - return 1; + return numScrollingPages - 1; } else { - return 0; + return numScrollingPages; } } - private int getNumScreensExcludingEmpty() { - return mWorkspace.getChildCount() - numEmptyScreensToIgnore(); - } - public void syncWithScroll() { - float offset = wallpaperOffsetForCurrentScroll(); - setFinalX(offset); - updateOffset(true); - } - - public float getCurrX() { - return mCurrentOffset; + int numScreens = getNumScreensExcludingEmpty(); + wallpaperOffsetForScroll(mWorkspace.getScrollX(), numScreens, sTempInt); + Message msg = Message.obtain(mHandler, MSG_UPDATE_OFFSET, sTempInt[0], sTempInt[1], + mWindowToken); + if (numScreens != mNumScreens) { + if (mNumScreens > 0) { + // Don't animate if we're going from 0 screens + msg.what = MSG_START_ANIMATION; + } + mNumScreens = numScreens; + updateOffset(); + } + msg.sendToTarget(); } - public float getFinalX() { - return mFinalOffset; + private void updateOffset() { + int numPagesForWallpaperParallax; + if (mWallpaperIsLiveWallpaper) { + numPagesForWallpaperParallax = mNumScreens; + } else { + numPagesForWallpaperParallax = Math.max(MIN_PARALLAX_PAGE_SPAN, mNumScreens); + } + Message.obtain(mHandler, MSG_SET_NUM_PARALLAX, numPagesForWallpaperParallax, 0, + mWindowToken).sendToTarget(); } - private void animateToFinal() { - mAnimating = true; - mAnimationStartOffset = mCurrentOffset; - mAnimationStartTime = System.currentTimeMillis(); + public void jumpToFinal() { + Message.obtain(mHandler, MSG_JUMP_TO_FINAL, mWindowToken).sendToTarget(); } - private void setWallpaperOffsetSteps() { - // Set wallpaper offset steps (1 / (number of screens - 1)) - float xOffset = 1.0f / (mNumPagesForWallpaperParallax - 1); - if (xOffset != mLastSetWallpaperOffsetSteps) { - mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f); - mLastSetWallpaperOffsetSteps = xOffset; + public void setWindowToken(IBinder token) { + mWindowToken = token; + if (mWindowToken == null && mRegistered) { + mWorkspace.getContext().unregisterReceiver(this); + mRegistered = false; + } else if (mWindowToken != null && !mRegistered) { + mWorkspace.getContext() + .registerReceiver(this, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED)); + onReceive(mWorkspace.getContext(), null); + mRegistered = true; } } - public void setFinalX(float x) { - scheduleUpdate(); - mFinalOffset = Math.max(0f, Math.min(x, 1f)); - if (getNumScreensExcludingEmpty() != mNumScreens) { - if (mNumScreens > 0 && Float.compare(mCurrentOffset, mFinalOffset) != 0) { - // Don't animate if we're going from 0 screens, or if the final offset is the same - // as the current offset - animateToFinal(); - } - mNumScreens = getNumScreensExcludingEmpty(); - } + @Override + public void onReceive(Context context, Intent intent) { + mWallpaperIsLiveWallpaper = + WallpaperManager.getInstance(mWorkspace.getContext()).getWallpaperInfo() != null; + updateOffset(); } - private void scheduleUpdate() { - if (!mWaitingForUpdate) { - mChoreographer.postFrameCallback(this); - mWaitingForUpdate = true; + private static final int MSG_START_ANIMATION = 1; + private static final int MSG_UPDATE_OFFSET = 2; + private static final int MSG_APPLY_OFFSET = 3; + private static final int MSG_SET_NUM_PARALLAX = 4; + private static final int MSG_JUMP_TO_FINAL = 5; + + private static class OffsetHandler extends Handler { + + private final Interpolator mInterpolator; + private final WallpaperManager mWM; + + private float mCurrentOffset = 0.5f; // to force an initial update + private boolean mAnimating; + private long mAnimationStartTime; + private float mAnimationStartOffset; + + private float mFinalOffset; + private float mOffsetX; + + public OffsetHandler(Context context) { + super(UiThreadHelper.getBackgroundLooper()); + mInterpolator = new DecelerateInterpolator(1.5f); + mWM = WallpaperManager.getInstance(context); } - } - public void jumpToFinal() { - mCurrentOffset = mFinalOffset; - } + @Override + public void handleMessage(Message msg) { + final IBinder token = (IBinder) msg.obj; + if (token == null) { + return; + } - public void onResume() { - mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null; - // Force the wallpaper offset steps to be set again, because another app might have changed - // them - mLastSetWallpaperOffsetSteps = 0f; - } + switch (msg.what) { + case MSG_START_ANIMATION: { + mAnimating = true; + mAnimationStartOffset = mCurrentOffset; + mAnimationStartTime = msg.getWhen(); + // Follow through + } + case MSG_UPDATE_OFFSET: + mFinalOffset = ((float) msg.arg1) / msg.arg2; + // Follow through + case MSG_APPLY_OFFSET: { + float oldOffset = mCurrentOffset; + if (mAnimating) { + long durationSinceAnimation = SystemClock.uptimeMillis() + - mAnimationStartTime; + float t0 = durationSinceAnimation / (float) ANIMATION_DURATION; + float t1 = mInterpolator.getInterpolation(t0); + mCurrentOffset = mAnimationStartOffset + + (mFinalOffset - mAnimationStartOffset) * t1; + mAnimating = durationSinceAnimation < ANIMATION_DURATION; + } else { + mCurrentOffset = mFinalOffset; + } + + if (Float.compare(mCurrentOffset, oldOffset) != 0) { + setOffsetSafely(token); + // Force the wallpaper offset steps to be set again, because another app + // might have changed them + mWM.setWallpaperOffsetSteps(mOffsetX, 1.0f); + } + if (mAnimating) { + // If we are animating, keep updating the offset + Message.obtain(this, MSG_APPLY_OFFSET, token).sendToTarget(); + } + return; + } + case MSG_SET_NUM_PARALLAX: { + // Set wallpaper offset steps (1 / (number of screens - 1)) + mOffsetX = 1.0f / (msg.arg1 - 1); + mWM.setWallpaperOffsetSteps(mOffsetX, 1.0f); + return; + } + case MSG_JUMP_TO_FINAL: { + if (Float.compare(mCurrentOffset, mFinalOffset) != 0) { + mCurrentOffset = mFinalOffset; + setOffsetSafely(token); + } + mAnimating = false; + return; + } + } + } - public void setWindowToken(IBinder token) { - mWindowToken = token; + private void setOffsetSafely(IBinder token) { + try { + mWM.setWallpaperOffsets(token, mCurrentOffset, 0.5f); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Error updating wallpaper offset: " + e); + } + } } }
\ No newline at end of file diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java index ad05ce917..bc404842e 100644 --- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java +++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java @@ -35,13 +35,13 @@ public class PendingAddWidgetInfo extends PendingAddItemInfo { public Bundle bindOptions = null; public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i) { - if (i.isCustomWidget) { + if (i.isCustomWidget()) { itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; } else { itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; } this.info = i; - user = i.getUser(); + user = i.getProfile(); componentName = i.provider; previewImage = i.previewImage; icon = i.icon; diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java index 19be28d83..c5cf5e23a 100644 --- a/src/com/android/launcher3/widget/PendingItemDragHelper.java +++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java @@ -22,7 +22,6 @@ import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.os.Build; import android.view.View; import android.widget.RemoteViews; @@ -32,11 +31,9 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; -import com.android.launcher3.Workspace; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.LivePreviewWidgetCell; import com.android.launcher3.graphics.DragPreviewProvider; -import com.android.launcher3.graphics.HolographicOutlineHelper; import com.android.launcher3.graphics.LauncherIcons; /** @@ -48,8 +45,8 @@ public class PendingItemDragHelper extends DragPreviewProvider { private static final float MAX_WIDGET_SCALE = 1.25f; private final PendingAddItemInfo mAddInfo; + private int[] mEstimatedCellSize; - private Bitmap mPreviewBitmap; private RemoteViews mPreview; public PendingItemDragHelper(View view) { @@ -80,12 +77,12 @@ public class PendingItemDragHelper extends DragPreviewProvider { final Point dragOffset; final Rect dragRegion; + mEstimatedCellSize = launcher.getWorkspace().estimateItemSize(mAddInfo); if (mAddInfo instanceof PendingAddWidgetInfo) { PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) mAddInfo; - int[] size = launcher.getWorkspace().estimateItemSize(createWidgetInfo, true, false); - int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), size[0]); + int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), mEstimatedCellSize[0]); int[] previewSizeBeforeScale = new int[1]; @@ -117,14 +114,12 @@ public class PendingItemDragHelper extends DragPreviewProvider { PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo; Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache()); preview = LauncherIcons.createScaledBitmapWithoutShadow(icon, launcher, 0); - mAddInfo.spanX = mAddInfo.spanY = 1; scale = ((float) launcher.getDeviceProfile().iconSizePx) / preview.getWidth(); dragOffset = new Point(previewPadding / 2, previewPadding / 2); // Create a preview same as the workspace cell size and draw the icon at the // appropriate position. - int[] size = launcher.getWorkspace().estimateItemSize(mAddInfo, false, true); DeviceProfile dp = launcher.getDeviceProfile(); int iconSize = dp.iconSizePx; @@ -134,9 +129,10 @@ public class PendingItemDragHelper extends DragPreviewProvider { previewBounds.top += padding; dragRegion = new Rect(); - dragRegion.left = (size[0] - iconSize) / 2; + dragRegion.left = (mEstimatedCellSize[0] - iconSize) / 2; dragRegion.right = dragRegion.left + iconSize; - dragRegion.top = (size[1] - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2; + dragRegion.top = (mEstimatedCellSize[1] + - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2; dragRegion.bottom = dragRegion.top + iconSize; } @@ -149,60 +145,31 @@ public class PendingItemDragHelper extends DragPreviewProvider { int dragLayerY = screenPos.y + previewBounds.top + (int) ((scale * preview.getHeight() - preview.getHeight()) / 2); - mPreviewBitmap = preview; // Start the drag launcher.getDragController().startDrag(preview, dragLayerX, dragLayerY, source, mAddInfo, dragOffset, dragRegion, scale, options); } - @Override - public Bitmap createDragOutline(Canvas canvas) { - if (mAddInfo instanceof PendingAddShortcutInfo) { - int width = mPreviewBitmap.getWidth(); - int height = mPreviewBitmap.getHeight(); - Bitmap b = Bitmap.createBitmap(width + blurSizeOutline, height + blurSizeOutline, - Bitmap.Config.ALPHA_8); - canvas.setBitmap(b); - - Launcher launcher = Launcher.getLauncher(mView.getContext()); - int size = launcher.getDeviceProfile().iconSizePx; - - Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight()); - Rect dst = new Rect(0, 0, size, size); - dst.offset(blurSizeOutline / 2, blurSizeOutline / 2); - canvas.drawBitmap(mPreviewBitmap, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG)); - - HolographicOutlineHelper.getInstance(mView.getContext()) - .applyExpensiveOutlineWithBlur(b, canvas); - - canvas.setBitmap(null); - return b; + protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) { + if (mAddInfo instanceof PendingAddShortcutInfo || mEstimatedCellSize == null) { + return super.convertPreviewToAlphaBitmap(preview); } - Workspace workspace = Launcher.getLauncher(mView.getContext()).getWorkspace(); - int[] size = workspace.estimateItemSize(mAddInfo, false, false); - - int w = size[0]; - int h = size[1]; + int w = mEstimatedCellSize[0]; + int h = mEstimatedCellSize[1]; final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8); - canvas.setBitmap(b); + Rect src = new Rect(0, 0, preview.getWidth(), preview.getHeight()); - Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight()); - float scaleFactor = Math.min((w - blurSizeOutline) / (float) mPreviewBitmap.getWidth(), - (h - blurSizeOutline) / (float) mPreviewBitmap.getHeight()); - int scaledWidth = (int) (scaleFactor * mPreviewBitmap.getWidth()); - int scaledHeight = (int) (scaleFactor * mPreviewBitmap.getHeight()); + float scaleFactor = Math.min((w - blurSizeOutline) / (float) preview.getWidth(), + (h - blurSizeOutline) / (float) preview.getHeight()); + int scaledWidth = (int) (scaleFactor * preview.getWidth()); + int scaledHeight = (int) (scaleFactor * preview.getHeight()); Rect dst = new Rect(0, 0, scaledWidth, scaledHeight); // center the image dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2); - - canvas.drawBitmap(mPreviewBitmap, src, dst, null); - HolographicOutlineHelper.getInstance(mView.getContext()) - .applyExpensiveOutlineWithBlur(b, canvas); - canvas.setBitmap(null); - + new Canvas(b).drawBitmap(preview, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG)); return b; } } diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java index 5eeea44b8..8dcdd4465 100644 --- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java +++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java @@ -85,7 +85,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { private boolean preloadWidget() { final LauncherAppWidgetProviderInfo pInfo = mInfo.info; - if (pInfo.isCustomWidget) { + if (pInfo.isCustomWidget()) { return false; } final Bundle options = getDefaultOptionsForWidget(mLauncher, mInfo); @@ -129,7 +129,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { mWidgetLoadingId = -1; hostView.setVisibility(View.INVISIBLE); - int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo, false, true); + int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo); // We want the first widget layout to be the correct size. This will be important // for width size reporting to the AppWidgetManager. DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0], diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 01101ac74..7aa50a445 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -40,24 +40,23 @@ import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.graphics.GradientView; import com.android.launcher3.model.WidgetItem; -import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.touch.SwipeDetector; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; -import com.android.launcher3.util.TouchController; import java.util.List; /** * Bottom sheet for the "Widgets" system shortcut in the long-press popup. */ -public class WidgetsBottomSheet extends AbstractFloatingView implements Insettable, TouchController, +public class WidgetsBottomSheet extends AbstractFloatingView implements Insettable, SwipeDetector.Listener, View.OnClickListener, View.OnLongClickListener, DragController.DragListener { @@ -108,7 +107,6 @@ 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); @@ -242,18 +240,6 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab } @Override - public int getLogContainerType() { - return LauncherLogProto.ContainerType.WIDGETS; // TODO: be more specific - } - - /** - * Returns a {@link WidgetsBottomSheet} which is already open or null - */ - public static WidgetsBottomSheet getOpen(Launcher launcher) { - return getOpenView(launcher, TYPE_WIDGETS_BOTTOM_SHEET); - } - - @Override public void setInsets(Rect insets) { // Extend behind left, right, and bottom insets. int leftInset = insets.left - mInsets.left; @@ -302,12 +288,27 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab } @Override + public void logActionCommand(int command) { + // TODO: be more specific + mLauncher.getUserEventDispatcher().logActionCommand(command, ContainerType.WIDGETS); + } + + @Override public boolean onControllerTouchEvent(MotionEvent ev) { return mSwipeDetector.onTouchEvent(ev); } @Override public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_UP) { + // If we got ACTION_UP without ever returning true on intercept, + // the user never started dragging the bottom sheet. + if (!mLauncher.getDragLayer().isEventOverView(this, ev)) { + close(true); + return false; + } + } + int directionsToDetectScroll = mSwipeDetector.isIdleState() ? SwipeDetector.DIRECTION_NEGATIVE : 0; mSwipeDetector.setDetectableScrollConditions( diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index acec3dd3b..39dd0d498 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -197,25 +197,6 @@ public class WidgetsContainerView extends BaseContainerView // @Override - public boolean supportsAppInfoDropTarget() { - return true; - } - - /* - * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the - * {@link DeleteDropTarget} to be invisible.) - */ - @Override - public boolean supportsDeleteDropTarget() { - return false; - } - - @Override - public float getIntrinsicIconScaleFactor() { - return 0; - } - - @Override public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, boolean success) { if (LOGD) { diff --git a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java new file mode 100644 index 000000000..1086987f8 --- /dev/null +++ b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java @@ -0,0 +1,103 @@ +/* + * 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.widget.custom; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.Utilities; + +/** + * Custom app widget provider info that can be used as a widget, but provide extra functionality + * by allowing custom code and views. + */ +public class CustomAppWidgetProviderInfo extends LauncherAppWidgetProviderInfo + implements Parcelable { + + public final int providerId; + + protected CustomAppWidgetProviderInfo(Parcel parcel, boolean readSelf, int providerId) { + super(parcel); + if (readSelf) { + this.providerId = parcel.readInt(); + + provider = new ComponentName(parcel.readString(), CLS_CUSTOM_WIDGET_PREFIX + providerId); + + label = parcel.readString(); + initialLayout = parcel.readInt(); + icon = parcel.readInt(); + previewImage = parcel.readInt(); + + resizeMode = parcel.readInt(); + spanX = parcel.readInt(); + spanY = parcel.readInt(); + minSpanX = parcel.readInt(); + minSpanY = parcel.readInt(); + } else { + this.providerId = providerId; + } + } + + @Override + public void initSpans(Context context) { } + + @Override + public String getLabel(PackageManager packageManager) { + return Utilities.trim(label); + } + + @Override + public String toString() { + return "WidgetProviderInfo(" + provider + ")"; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(providerId); + out.writeString(provider.getPackageName()); + + out.writeString(label); + out.writeInt(initialLayout); + out.writeInt(icon); + out.writeInt(previewImage); + + out.writeInt(resizeMode); + out.writeInt(spanX); + out.writeInt(spanY); + out.writeInt(minSpanX); + out.writeInt(minSpanY); + } + + public static final Parcelable.Creator<CustomAppWidgetProviderInfo> CREATOR + = new Parcelable.Creator<CustomAppWidgetProviderInfo>() { + + @Override + public CustomAppWidgetProviderInfo createFromParcel(Parcel parcel) { + return new CustomAppWidgetProviderInfo(parcel, true, 0); + } + + @Override + public CustomAppWidgetProviderInfo[] newArray(int size) { + return new CustomAppWidgetProviderInfo[size]; + } + }; +} diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetParser.java b/src/com/android/launcher3/widget/custom/CustomWidgetParser.java new file mode 100644 index 000000000..00720c449 --- /dev/null +++ b/src/com/android/launcher3/widget/custom/CustomWidgetParser.java @@ -0,0 +1,142 @@ +/* + * 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.widget.custom; + +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.ComponentName; +import android.content.Context; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Parcel; +import android.os.Process; +import android.util.SparseArray; +import android.util.Xml; + +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX; + +/** + * Utility class to parse {@ink CustomAppWidgetProviderInfo} definitions from xml + */ +public class CustomWidgetParser { + + private static List<LauncherAppWidgetProviderInfo> sCustomWidgets; + private static SparseArray<ComponentName> sWidgetsIdMap; + + public static List<LauncherAppWidgetProviderInfo> getCustomWidgets(Context context) { + if (sCustomWidgets == null) { + // Synchronization not needed as it it safe to load multiple times + parseCustomWidgets(context); + } + + return sCustomWidgets; + } + + public static int getWidgetIdForCustomProvider(Context context, ComponentName provider) { + if (sWidgetsIdMap == null) { + parseCustomWidgets(context); + } + int index = sWidgetsIdMap.indexOfValue(provider); + if (index >= 0) { + return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - sWidgetsIdMap.keyAt(index); + } else { + return AppWidgetManager.INVALID_APPWIDGET_ID; + } + } + + public static LauncherAppWidgetProviderInfo getWidgetProvider(Context context, int widgetId) { + if (sWidgetsIdMap == null || sCustomWidgets == null) { + parseCustomWidgets(context); + } + ComponentName cn = sWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId); + for (LauncherAppWidgetProviderInfo info : sCustomWidgets) { + if (info.provider.equals(cn)) { + return info; + } + } + return null; + } + + private static void parseCustomWidgets(Context context) { + ArrayList<LauncherAppWidgetProviderInfo> widgets = new ArrayList<>(); + SparseArray<ComponentName> idMap = new SparseArray<>(); + + List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context) + .getInstalledProvidersForProfile(Process.myUserHandle()); + if (providers.isEmpty()) { + sCustomWidgets = widgets; + sWidgetsIdMap = idMap; + return; + } + + Parcel parcel = Parcel.obtain(); + providers.get(0).writeToParcel(parcel, 0); + + try (XmlResourceParser parser = context.getResources().getXml(R.xml.custom_widgets)) { + final int depth = parser.getDepth(); + int type; + + while (((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { + if ((type == XmlPullParser.START_TAG) && "widget".equals(parser.getName())) { + TypedArray a = context.obtainStyledAttributes( + Xml.asAttributeSet(parser), R.styleable.CustomAppWidgetProviderInfo); + + parcel.setDataPosition(0); + CustomAppWidgetProviderInfo info = newInfo(a, parcel, context); + widgets.add(info); + a.recycle(); + + idMap.put(info.providerId, info.provider); + } + } + } catch (IOException | XmlPullParserException e) { + throw new RuntimeException(e); + } + parcel.recycle(); + sCustomWidgets = widgets; + sWidgetsIdMap = idMap; + } + + private static CustomAppWidgetProviderInfo newInfo(TypedArray a, Parcel parcel, Context context) { + int providerId = a.getInt(R.styleable.CustomAppWidgetProviderInfo_providerId, 0); + CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false, providerId); + info.provider = new ComponentName(context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId); + + info.label = a.getString(R.styleable.CustomAppWidgetProviderInfo_android_label); + info.initialLayout = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_initialLayout, 0); + info.icon = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_icon, 0); + info.previewImage = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_previewImage, 0); + info.resizeMode = a.getInt(R.styleable.CustomAppWidgetProviderInfo_android_resizeMode, 0); + + info.spanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numColumns, 1); + info.spanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numRows, 1); + info.minSpanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinColumns, 1); + info.minSpanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinRows, 1); + return info; + } +} |