Merge changes I218fe7d9,I60ef59de into ub-launcher3-master
* changes:
Make work footer stick to the bottom if there are only a few apps #2
Make work footer stick to the bottom if there are only a few apps
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
index 20cda1c..435d57e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
@@ -367,7 +367,7 @@
mCurrentAnimation.setEndAction(() -> {
// TODO: Add logging
clearState();
- mLauncher.getStateManager().goToState(OVERVIEW, false /* animated */);
+ mLauncher.getStateManager().goToState(OVERVIEW, true /* animated */);
});
if (mTwoStateAnimationController != null) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 9178d8a..9be0d32 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -17,6 +17,8 @@
package com.android.launcher3.uioverrides;
import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.view.View.AccessibilityDelegate;
import android.widget.PopupMenu;
import android.widget.Toast;
@@ -24,11 +26,16 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.graphics.BitmapRenderer;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.widget.WidgetsFullSheet;
+import com.android.systemui.shared.recents.view.RecentsTransition;
public class UiFactory {
+ public static final boolean USE_HARDWARE_BITMAP = FeatureFlags.IS_DOGFOOD_BUILD;
+
public static TouchController[] createTouchControllers(Launcher launcher) {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
@@ -77,4 +84,15 @@
}
menu.show();
}
+
+ public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer,
+ BitmapRenderer renderer) {
+ if (USE_HARDWARE_BITMAP && !forceSoftwareRenderer) {
+ return RecentsTransition.createHardwareBitmap(width, height, renderer::render);
+ } else {
+ Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ renderer.render(new Canvas(result));
+ return result;
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 75db45b..43a01a7 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -199,9 +199,9 @@
private void executeFrameUpdate() {
if (mLauncherReady) {
final float displacement = -mCurrentDisplacement;
- int hotseatHeight = mHotseat.getHeight();
- float translation = Utilities.boundToRange(displacement, 0, hotseatHeight);
- float shift = hotseatHeight == 0 ? 0 : translation / hotseatHeight;
+ int hotseatSize = getHotseatSize();
+ float translation = Utilities.boundToRange(displacement, 0, hotseatSize);
+ float shift = hotseatSize == 0 ? 0 : translation / hotseatSize;
mCurrentShift.updateValue(shift);
}
}
@@ -215,13 +215,14 @@
if (mTargetRect.isEmpty()) {
RecentsView.getPageRect(mLauncher, mTargetRect);
DragLayer dl = mLauncher.getDragLayer();
- mSourceRect.set(0, 0, dl.getWidth(), dl.getHeight());
+ mSourceRect.set(0, 0, dl.getWidth() - mStableInsets.left - mStableInsets.right,
+ dl.getHeight() - mStableInsets.top - mStableInsets.bottom);
}
float shift = mCurrentShift.value * mActivityMultiplier.value;
- int hotseatHeight = mHotseat.getHeight();
+ int hotseatSize = getHotseatSize();
- mHotseat.setTranslationY((1 - shift) * hotseatHeight);
+ mHotseat.setTranslationY((1 - shift) * hotseatSize);
mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
@@ -230,10 +231,17 @@
mDragView.setTranslationY(mCurrentRect.top - mStableInsets.top * scale * shift);
mDragView.setScaleX(scale);
mDragView.setScaleY(scale);
+ // TODO: mDragView.getViewBounds().setClipLeft((int) (mStableInsets.left * shift));
mDragView.getViewBounds().setClipTop((int) (mStableInsets.top * shift));
+ // TODO: mDragView.getViewBounds().setClipRight((int) (mStableInsets.right * shift));
mDragView.getViewBounds().setClipBottom((int) (mStableInsets.bottom * shift));
}
+ private int getHotseatSize() {
+ return mLauncher.getDeviceProfile().isVerticalBarLayout()
+ ? mHotseat.getWidth() : mHotseat.getHeight();
+ }
+
@UiThread
public void setRecentsTaskLoadPlan(RecentsTaskLoadPlan loadPlan) {
mLoadPlan = loadPlan;
@@ -272,7 +280,7 @@
endShift = endVelocity < 0 ? 1 : 0;
float minFlingVelocity = res.getDimension(R.dimen.quickstep_fling_min_velocity);
if (Math.abs(endVelocity) > minFlingVelocity && mLauncherReady) {
- float distanceToTravel = (endShift - mCurrentShift.value) * mHotseat.getHeight();
+ float distanceToTravel = (endShift - mCurrentShift.value) * getHotseatSize();
// we want the page's snap velocity to approximately match the velocity at
// which the user flings, so we scale the duration by a value near to the
@@ -320,5 +328,9 @@
private void onAnimationToLauncherComplete() {
mDragView.close(false);
+ View currentRecentsPage = mRecentsView.getPageAt(mRecentsView.getCurrentPage());
+ if (currentRecentsPage instanceof TaskView) {
+ ((TaskView) currentRecentsPage).animateIconToScale(1f);
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index a107343..fd9010d 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -146,6 +146,9 @@
public void update(RecentsTaskLoadPlan loadPlan) {
final RecentsTaskLoader loader = TouchInteractionService.getRecentsTaskLoader();
setCurrentPage(0);
+ if (getPageAt(mCurrentPage) instanceof TaskView) {
+ ((TaskView) getPageAt(mCurrentPage)).setIconScale(0);
+ }
TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
if (stack == null) {
removeAllViews();
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
index 6e8bbeb..4a9bfea 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
@@ -25,7 +25,6 @@
import android.graphics.LightingColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
@@ -154,17 +153,15 @@
final Configuration configuration =
getContext().getApplicationContext().getResources().getConfiguration();
final DeviceProfile profile = Launcher.getLauncher(getContext()).getDeviceProfile();
- if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
- if (mThumbnailData.orientation == Configuration.ORIENTATION_PORTRAIT) {
- // If we are in the same orientation as the screenshot, just scale it to the
- // width of the task view
- mThumbnailScale = (float) getMeasuredWidth() / mThumbnailRect.width();
- } else {
- // Scale the landscape thumbnail up to app size, then scale that to the task
- // view size to match other portrait screenshots
- mThumbnailScale = invThumbnailScale *
- ((float) getMeasuredWidth() / profile.getCurrentWidth());
- }
+ if (configuration.orientation == mThumbnailData.orientation) {
+ // If we are in the same orientation as the screenshot, just scale it to the
+ // width of the task view
+ mThumbnailScale = (float) getMeasuredWidth() / mThumbnailRect.width();
+ } else if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ // Scale the landscape thumbnail up to app size, then scale that to the task
+ // view size to match other portrait screenshots
+ mThumbnailScale = invThumbnailScale *
+ ((float) getMeasuredWidth() / profile.getCurrentWidth());
} else {
// Otherwise, scale the screenshot to fit 1:1 in the current orientation
mThumbnailScale = invThumbnailScale;
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index a0ad618..d834881 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -59,6 +59,8 @@
*/
private static final float SWIPE_DISTANCE_HEIGHT_PERCENTAGE = 0.38f;
+ private static final long SCALE_ICON_DURATION = 120;
+
private static final Property<TaskView, Float> PROPERTY_SWIPE_PROGRESS =
new Property<TaskView, Float>(Float.class, "swipe_progress") {
@@ -73,6 +75,19 @@
}
};
+ private static final Property<TaskView, Float> SCALE_ICON_PROPERTY =
+ new Property<TaskView, Float>(Float.TYPE, "scale_icon") {
+ @Override
+ public Float get(TaskView taskView) {
+ return taskView.mIconScale;
+ }
+
+ @Override
+ public void set(TaskView taskView, Float iconScale) {
+ taskView.setIconScale(iconScale);
+ }
+ };
+
private Task mTask;
private TaskThumbnailView mSnapshotView;
private ImageView mIconView;
@@ -81,6 +96,7 @@
private float mSwipeProgress;
private Interpolator mAlphaInterpolator;
private Interpolator mSwipeAnimInterpolator;
+ private float mIconScale = 1f;
public TaskView(Context context) {
this(context, null);
@@ -259,4 +275,17 @@
swipeAnimator.setInterpolator(mSwipeAnimInterpolator);
swipeAnimator.start();
}
+
+ public void animateIconToScale(float scale) {
+ ObjectAnimator.ofFloat(this, SCALE_ICON_PROPERTY, scale)
+ .setDuration(SCALE_ICON_DURATION).start();
+ }
+
+ protected void setIconScale(float iconScale) {
+ mIconScale = iconScale;
+ if (mIconView != null) {
+ mIconView.setScaleX(mIconScale);
+ mIconView.setScaleY(mIconScale);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7b220d8..f457a59 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -44,6 +44,7 @@
import android.view.Choreographer;
import android.view.Display;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
@@ -61,6 +62,7 @@
import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.function.Consumer;
@@ -105,6 +107,8 @@
private int mTouchSlop;
private float mStartDisplacement;
private NavBarSwipeInteractionHandler mInteractionHandler;
+ private int mDisplayRotation;
+ private Rect mStableInsets = new Rect();
private ISystemUiProxy mISystemUiProxy;
private Consumer<MotionEvent> mCurrentConsumer = mNoOpTouchConsumer;
@@ -181,6 +185,10 @@
mInteractionHandler.endTouch(0);
mInteractionHandler = null;
}
+
+ Display display = getSystemService(WindowManager.class).getDefaultDisplay();
+ mDisplayRotation = display.getRotation();
+ WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
break;
}
case ACTION_POINTER_UP: {
@@ -206,6 +214,11 @@
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
float displacement = ev.getY(pointerIndex) - mDownPos.y;
+ if (isNavBarOnRight()) {
+ displacement = ev.getX(pointerIndex) - mDownPos.x;
+ } else if (isNavBarOnLeft()) {
+ displacement = mDownPos.x - ev.getX(pointerIndex);
+ }
if (mInteractionHandler == null) {
if (Math.abs(displacement) >= mTouchSlop) {
mStartDisplacement = Math.signum(displacement) * mTouchSlop;
@@ -229,6 +242,13 @@
}
}
+ private boolean isNavBarOnRight() {
+ return mDisplayRotation == Surface.ROTATION_90 && mStableInsets.right > 0;
+ }
+
+ private boolean isNavBarOnLeft() {
+ return mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
+ }
private void startTouchTracking() {
// Create the shared handler
@@ -272,7 +292,10 @@
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
- mInteractionHandler.endTouch(mVelocityTracker.getYVelocity(mActivePointerId));
+ float velocity = isNavBarOnRight() ? mVelocityTracker.getXVelocity(mActivePointerId)
+ : isNavBarOnLeft() ? -mVelocityTracker.getXVelocity(mActivePointerId)
+ : mVelocityTracker.getYVelocity(mActivePointerId);
+ mInteractionHandler.endTouch(velocity);
mInteractionHandler = null;
}
mVelocityTracker.recycle();
@@ -290,9 +313,16 @@
Point displaySize = new Point();
Display display = getSystemService(WindowManager.class).getDefaultDisplay();
display.getRealSize(displaySize);
+ int rotation = display.getRotation();
+ // The rotation is backwards in landscape, so flip it.
+ if (rotation == Surface.ROTATION_270) {
+ rotation = Surface.ROTATION_90;
+ } else if (rotation == Surface.ROTATION_90) {
+ rotation = Surface.ROTATION_270;
+ }
try {
return mISystemUiProxy.screenshot(new Rect(), displaySize.x, displaySize.y, 0, 100000,
- false, display.getRotation()).toBitmap();
+ false, rotation).toBitmap();
} catch (RemoteException e) {
Log.e(TAG, "Error capturing snapshot", e);
return null;
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index d21e45d..f6bdd25 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -50,7 +50,11 @@
android:layout_gravity="bottom|left"
android:background="@drawable/all_apps_handle_landscape" />
- <include layout="@layout/gradient_bg" />
+ <com.android.launcher3.views.AllAppsScrim
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/all_apps_scrim"
+ launcher:layout_ignoreInsets="true" />
<!-- DO NOT CHANGE THE ID -->
<include layout="@layout/hotseat"
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index f58a87e..5d670e6 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -44,7 +44,11 @@
launcher:pageIndicator="@+id/page_indicator">
</com.android.launcher3.Workspace>
- <include layout="@layout/gradient_bg" />
+ <com.android.launcher3.views.AllAppsScrim
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/all_apps_scrim"
+ launcher:layout_ignoreInsets="true" />
<!-- DO NOT CHANGE THE ID -->
<include layout="@layout/hotseat"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 660d0ed..483fb96 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -43,7 +43,11 @@
launcher:pageIndicator="@id/page_indicator">
</com.android.launcher3.Workspace>
- <include layout="@layout/gradient_bg" />
+ <com.android.launcher3.views.AllAppsScrim
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/all_apps_scrim"
+ launcher:layout_ignoreInsets="true" />
<!-- DO NOT CHANGE THE ID -->
<include layout="@layout/hotseat"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 3f6be2c..8cf32bd 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -41,14 +41,6 @@
<include layout="@layout/predictions_view" android:id="@+id/header_content" />
- <include layout="@layout/all_apps_divider"
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
- android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
- android:layout_alignBottom="@+id/tabs" />
-
<com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 93c5114..1ae7cbf 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -50,6 +50,10 @@
<dimen name="dynamic_grid_hotseat_land_left_nav_bar_left_padding">0dp</dimen>
<dimen name="dynamic_grid_hotseat_land_right_nav_bar_left_padding">0dp</dimen>
+ <!-- Hotseat/all-apps scrim -->
+ <dimen name="all_apps_scrim_radius">10dp</dimen>
+ <dimen name="all_apps_scrim_margin">10dp</dimen>
+ <dimen name="all_apps_scrim_blur">5dp</dimen>
<!-- Drop target bar -->
<dimen name="dynamic_grid_drop_target_size">48dp</dimen>
@@ -97,6 +101,7 @@
<dimen name="all_apps_work_profile_tab_footer_top_padding">16dp</dimen>
<dimen name="all_apps_work_profile_tab_footer_bottom_padding">20dp</dimen>
<dimen name="all_apps_tabs_side_padding">12dp</dimen>
+ <dimen name="all_apps_divider_height">1dp</dimen>
<!-- Search bar in All Apps -->
<dimen name="all_apps_header_max_elevation">3dp</dimen>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c6226f4..7b3da67 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -33,6 +33,7 @@
import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.badge.BadgeRenderer;
+import com.android.launcher3.views.AllAppsScrim;
import java.util.ArrayList;
@@ -588,14 +589,16 @@
searchBar.setLayoutParams(lp);
// Layout the workspace
- PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
+ PagedView workspace = launcher.getWorkspace();
Rect workspacePadding = getWorkspacePadding(null);
workspace.setPadding(workspacePadding.left, workspacePadding.top, workspacePadding.right,
workspacePadding.bottom);
workspace.setPageSpacing(getWorkspacePageSpacing());
+ AllAppsScrim allAppsScrim = launcher.findViewById(R.id.all_apps_scrim);
+
// Layout the hotseat
- Hotseat hotseat = (Hotseat) launcher.findViewById(R.id.hotseat);
+ Hotseat hotseat = launcher.getHotseat();
lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
// We want the edges of the hotseat to line up with the edges of the workspace, but the
// icons in the hotseat are a different size, and so don't line up perfectly. To account for
@@ -604,6 +607,8 @@
float workspaceCellWidth = (float) getCurrentWidth() / inv.numColumns;
float hotseatCellWidth = (float) getCurrentWidth() / inv.numHotseatIcons;
int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
+ float scrimMargin = launcher.getResources().getDimension(R.dimen.all_apps_scrim_margin);
+
if (hasVerticalBarLayout) {
// Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
// screen regardless of RTL
@@ -629,6 +634,8 @@
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
lp.height = hotseatBarSizePx + mInsets.bottom;
+ allAppsScrim.setDrawRegion(lp.height + scrimMargin);
+
hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
+ cellLayoutPaddingLeftRightPx,
hotseatBarTopPaddingPx,
@@ -640,6 +647,8 @@
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
lp.height = hotseatBarSizePx + mInsets.bottom;
+ allAppsScrim.setDrawRegion(lp.height + scrimMargin);
+
hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
+ cellLayoutPaddingLeftRightPx,
hotseatBarTopPaddingPx,
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 573e8a2..ab853e5 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -41,17 +41,20 @@
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
+
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Provider;
import com.android.launcher3.util.SQLiteCacheHelper;
import com.android.launcher3.util.Thunk;
+
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -102,6 +105,7 @@
@Thunk final Handler mWorkerHandler;
private final BitmapFactory.Options mLowResOptions;
+ private final BitmapFactory.Options mHighResOptions;
public IconCache(Context context, InvariantDeviceProfile inv) {
mContext = context;
@@ -120,6 +124,13 @@
// Always prefer RGB_565 config for low res. If the bitmap has transparency, it will
// automatically be loaded as ALPHA_8888.
mLowResOptions.inPreferredConfig = Bitmap.Config.RGB_565;
+
+ if (UiFactory.USE_HARDWARE_BITMAP) {
+ mHighResOptions = new BitmapFactory.Options();
+ mHighResOptions.inPreferredConfig = Bitmap.Config.HARDWARE;
+ } else {
+ mHighResOptions = null;
+ }
}
private Drawable getFullResDefaultActivityIcon() {
@@ -625,7 +636,7 @@
Bitmap icon = LauncherIcons.createBadgedIconBitmap(
appInfo.loadIcon(mPackageManager), user, mContext, appInfo.targetSdkVersion);
if (mInstantAppResolver.isInstantApp(appInfo)) {
- icon = LauncherIcons.badgeWithDrawable(icon,
+ LauncherIcons.badgeWithDrawable(icon,
mContext.getDrawable(R.drawable.ic_instant_app_badge), mContext);
}
Bitmap lowResIcon = generateLowResIcon(icon);
@@ -665,7 +676,7 @@
new String[]{cacheKey.componentName.flattenToString(),
Long.toString(mUserManager.getSerialNumberForUser(cacheKey.user))});
if (c.moveToNext()) {
- entry.icon = loadIconNoResize(c, 0, lowRes ? mLowResOptions : null);
+ entry.icon = loadIconNoResize(c, 0, lowRes ? mLowResOptions : mHighResOptions);
entry.isLowResIcon = lowRes;
entry.title = c.getString(1);
if (entry.title == null) {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 8a20bb9..80818f2 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.Partner.TAG;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.Animator;
@@ -26,7 +25,6 @@
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.util.Log;
import android.util.Property;
import android.view.View;
@@ -165,7 +163,6 @@
public static class PropertySetter {
public void setViewAlpha(Animator anim, View view, float alpha) {
- Log.d(TAG, "setViewAlpha: " + anim + " " + alpha);
if (anim != null) {
anim.end();
return;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 7b89c5c..8154845 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -495,6 +495,7 @@
public void onPageSelected(int pos) {
tabs.updateTabTextColor(pos);
mHeader.setMainActive(pos == 0);
+ reset();
applyTouchDelegate();
if (mAH[pos].recyclerView != null) {
mAH[pos].recyclerView.bindFastScrollbar();
@@ -546,7 +547,7 @@
return mHeader;
}
- private void setupHeader() {
+ public void setupHeader() {
if (mHeader == null) {
return;
}
@@ -674,8 +675,9 @@
recyclerView.setPadding(padding.left, paddingTop, padding.right, padding.bottom);
}
if (isHeaderVisible()) {
- mHeader.getPredictionRow()
- .setPadding(padding.left, 0 , padding.right, 0);
+ PredictionRowView prv = mHeader.getPredictionRow();
+ prv.setPadding(padding.left, prv.getPaddingTop() , padding.right,
+ prv.getPaddingBottom());
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 5de58b4..5830f74 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -24,6 +24,7 @@
import com.android.launcher3.graphics.GradientView;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.AllAppsScrim;
/**
* Handles AllApps view transition.
@@ -74,7 +75,7 @@
private static final float DEFAULT_SHIFT_RANGE = 10;
- private GradientView mGradientView;
+ private AllAppsScrim mAllAppsScrim;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
@@ -106,14 +107,6 @@
}
}
- private void updateAllAppsBg(float progress) {
- // gradient
- if (mGradientView == null) {
- mGradientView = mLauncher.findViewById(R.id.gradient_bg);
- }
- mGradientView.setProgress(progress);
- }
-
/**
* Note this method should not be called outside this class. This is public because it is used
* in xml-based animations which also handle updating the appropriate UI.
@@ -131,17 +124,21 @@
float alpha = 1 - workspaceHotseatAlpha;
float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
- updateAllAppsBg(alpha);
mAppsView.setAlpha(alpha);
mAppsView.setTranslationY(shiftCurrent);
+ if (mAllAppsScrim == null) {
+ mAllAppsScrim = mLauncher.findViewById(R.id.all_apps_scrim);
+ }
+ float hotseatTranslation = -mShiftRange + shiftCurrent;
+ mAllAppsScrim.setProgress(hotseatTranslation, alpha);
+
if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, -mShiftRange + shiftCurrent,
+ mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y, hotseatTranslation,
hotseatAlpha);
} else {
mWorkspace.setHotseatTranslationAndAlpha(Workspace.Direction.Y,
- PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent),
- hotseatAlpha);
+ PARALLAX_COEFFICIENT * hotseatTranslation, hotseatAlpha);
}
updateLightStatusBar(shiftCurrent);
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index dc3afb5..1419a2a 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -18,7 +18,6 @@
import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.support.annotation.NonNull;
@@ -66,7 +65,6 @@
private PredictionRowView mPredictionRow;
private ViewGroup mTabLayout;
- private View mDivider;
private AllAppsRecyclerView mMainRV;
private AllAppsRecyclerView mWorkRV;
private AllAppsRecyclerView mCurrentRV;
@@ -90,7 +88,6 @@
protected void onFinishInflate() {
super.onFinishInflate();
mTabLayout = findViewById(R.id.tabs);
- mDivider = findViewById(R.id.divider);
mPredictionRow = findViewById(R.id.header_content);
}
@@ -98,16 +95,15 @@
HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) {
mTabsHidden = mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null;
mTabLayout.setVisibility(mTabsHidden ? View.GONE : View.VISIBLE);
- mPredictionRow.setPadding(0, 0, 0, mTabsHidden ? getResources()
- .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height) : 0);
mPredictionRow.setup(mAH[AllAppsContainerView.AdapterHolder.MAIN].adapter,
componentToAppMap, numPredictedAppsPerRow);
+ mPredictionRow.setShowDivider(mTabsHidden);
mMaxTranslation = mPredictionRow.getExpectedHeight();
mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
mParent = (ViewGroup) mMainRV.getParent();
setMainActive(true);
- setupDivider();
+ reset();
}
private AllAppsRecyclerView setupRV(AllAppsRecyclerView old, AllAppsRecyclerView updated) {
@@ -117,35 +113,14 @@
return updated;
}
- private void setupDivider() {
- Resources res = getResources();
- int verticalGap = res.getDimensionPixelSize(R.dimen.all_apps_divider_margin_vertical);
- int sideGap = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- mDivider.setPadding(sideGap, verticalGap,sideGap, mTabsHidden ? verticalGap : 0);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mDivider.getLayoutParams();
- lp.removeRule(RelativeLayout.ALIGN_BOTTOM);
- lp.addRule(RelativeLayout.ALIGN_BOTTOM, mTabsHidden ? R.id.header_content : R.id.tabs);
- mDivider.setLayoutParams(lp);
- }
-
public void setMainActive(boolean active) {
mCurrentRV = active ? mMainRV : mWorkRV;
- mSnappedScrolledY = mCurrentRV.getCurrentScrollY() - mMaxTranslation;
- setExpanded(true);
}
public PredictionRowView getPredictionRow() {
return mPredictionRow;
}
- public View getDivider() {
- return mDivider;
- }
-
- public void reset() {
- setExpanded(true);
- }
-
private boolean canSnapAt(int currentScrollY) {
return Math.abs(currentScrollY) <= mPredictionRow.getHeight();
}
@@ -185,7 +160,6 @@
mPredictionRow.setTranslationY(uncappedTranslationY);
}
mTabLayout.setTranslationY(mTranslationY);
- mDivider.setTranslationY(mTabsHidden ? uncappedTranslationY : mTranslationY);
mClip.top = mMaxTranslation + mTranslationY;
// clipping on a draw might cause additional redraw
mMainRV.setClipBounds(mClip);
@@ -194,16 +168,14 @@
}
}
- private void setExpanded(boolean expand) {
- int translateTo = expand ? 0 : -mMaxTranslation;
+ public void reset() {
+ int translateTo = 0;
mAnimator.setIntValues(mTranslationY, translateTo);
mAnimator.addUpdateListener(this);
mAnimator.setDuration(150);
mAnimator.start();
- mHeaderCollapsed = !expand;
- mSnappedScrolledY = expand
- ? mCurrentRV.getCurrentScrollY() - mMaxTranslation
- : mCurrentRV.getCurrentScrollY();
+ mHeaderCollapsed = false;
+ mSnappedScrolledY = -mMaxTranslation;
}
public boolean isExpanded() {
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 54948b0..057c64a 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -35,6 +35,7 @@
public class PersonalWorkSlidingTabStrip extends LinearLayout {
private final Paint mPersonalTabIndicatorPaint;
private final Paint mWorkTabIndicatorPaint;
+ private final Paint mDividerPaint;
private int mSelectedIndicatorHeight;
private int mIndicatorLeft = -1;
@@ -59,6 +60,10 @@
mWorkTabIndicatorPaint.setColor(getResources().getColor(R.color.work_profile_color));
mIsRtl = Utilities.isRtl(getResources());
+
+ mDividerPaint = new Paint();
+ mDividerPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
+ mDividerPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
}
public void updateIndicatorPosition(int position, float positionOffset) {
@@ -116,6 +121,9 @@
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
+ float y = getHeight() - mDividerPaint.getStrokeWidth();
+ canvas.drawLine(getPaddingLeft(), y, getWidth() - getPaddingRight(), y, mDividerPaint);
+
final float middleX = getWidth() / 2.0f;
if (mIndicatorLeft <= middleX) {
canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
diff --git a/src/com/android/launcher3/allapps/PredictionRowView.java b/src/com/android/launcher3/allapps/PredictionRowView.java
index 1aee948..4aacc6d 100644
--- a/src/com/android/launcher3/allapps/PredictionRowView.java
+++ b/src/com/android/launcher3/allapps/PredictionRowView.java
@@ -17,6 +17,8 @@
package com.android.launcher3.allapps;
import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
@@ -27,9 +29,11 @@
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ComponentKeyMapper;
+import com.android.launcher3.util.Themes;
import java.util.ArrayList;
import java.util.Collections;
@@ -46,8 +50,10 @@
private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>();
// The set of predicted apps resolved from the component names and the current set of apps
private final List<AppInfo> mPredictedApps = new ArrayList<>();
+ private final Paint mPaint;
// This adapter is only used to create an identical item w/ same behavior as in the all apps RV
private AllAppsGridAdapter mAdapter;
+ private boolean mShowDivider;
public PredictionRowView(@NonNull Context context) {
this(context, null);
@@ -56,6 +62,10 @@
public PredictionRowView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.HORIZONTAL);
+ setWillNotDraw(false);
+ mPaint = new Paint();
+ mPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
+ mPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
}
public void setup(AllAppsGridAdapter adapter, HashMap<ComponentKey, AppInfo> componentToAppMap,
@@ -82,6 +92,13 @@
return height;
}
+ public void setShowDivider(boolean showDivider) {
+ mShowDivider = showDivider;
+ int paddingBottom = showDivider ? getResources()
+ .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height) : 0;
+ setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
+ }
+
/**
* Sets the number of apps per row.
*/
@@ -169,4 +186,17 @@
}
return predictedApps;
}
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mShowDivider) {
+ int side = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
+ int y = getHeight() - (getPaddingBottom() / 2);
+ int x1 = getPaddingLeft() + side;
+ int x2 = getWidth() - getPaddingRight() - side;
+ canvas.drawLine(x1, y, x2, y, mPaint);
+ }
+ }
}
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index c905460..1c6f77c 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -36,10 +36,9 @@
import com.android.launcher3.R;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
+import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.Preconditions;
-import java.util.concurrent.Callable;
-
/**
* {@link AdaptiveIconDrawable} representation of a {@link FolderIcon}
*/
@@ -66,7 +65,7 @@
}
public static FolderAdaptiveIcon createFolderAdaptiveIcon(
- final Launcher launcher, final long folderId, Point dragViewSize) {
+ Launcher launcher, long folderId, Point dragViewSize) {
Preconditions.assertNonUiThread();
int margin = launcher.getResources()
.getDimensionPixelSize(R.dimen.blur_size_medium_outline);
@@ -75,21 +74,12 @@
final Bitmap badge = Bitmap.createBitmap(
dragViewSize.x - margin, dragViewSize.y - margin, Bitmap.Config.ARGB_8888);
- // The bitmap for the preview is generated larger than needed to allow for the spring effect
- float sizeScaleFactor = 1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction();
- final Bitmap preview = Bitmap.createBitmap(
- (int) (dragViewSize.x * sizeScaleFactor), (int) (dragViewSize.y * sizeScaleFactor),
- Bitmap.Config.ARGB_8888);
-
// Create the actual drawable on the UI thread to avoid race conditions with
// FolderIcon draw pass
try {
- return new MainThreadExecutor().submit(new Callable<FolderAdaptiveIcon>() {
- @Override
- public FolderAdaptiveIcon call() throws Exception {
- FolderIcon icon = launcher.findFolderIcon(folderId);
- return icon == null ? null : createDrawableOnUiThread(icon, badge, preview);
- }
+ return new MainThreadExecutor().submit(() -> {
+ FolderIcon icon = launcher.findFolderIcon(folderId);
+ return icon == null ? null : createDrawableOnUiThread(icon, badge, dragViewSize);
}).get();
} catch (Exception e) {
Log.e(TAG, "Unable to create folder icon", e);
@@ -101,7 +91,7 @@
* Initializes various bitmaps on the UI thread and returns the final drawable.
*/
private static FolderAdaptiveIcon createDrawableOnUiThread(FolderIcon icon,
- Bitmap badgeBitmap, Bitmap previewBitmap) {
+ Bitmap badgeBitmap, Point dragViewSize) {
Preconditions.assertUIThread();
float margin = icon.getResources().getDimension(R.dimen.blur_size_medium_outline) / 2;
@@ -115,15 +105,21 @@
icon.drawBadge(c);
// Initialize preview
- float shiftFactor = AdaptiveIconDrawable.getExtraInsetFraction() /
- (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
- float previewShiftX = shiftFactor * previewBitmap.getWidth();
- float previewShiftY = shiftFactor * previewBitmap.getHeight();
+ final float sizeScaleFactor = 1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction();
+ final int previewWidth = (int) (dragViewSize.x * sizeScaleFactor);
+ final int previewHeight = (int) (dragViewSize.y * sizeScaleFactor);
- c.setBitmap(previewBitmap);
- c.translate(previewShiftX, previewShiftY);
- icon.getPreviewItemManager().draw(c);
- c.setBitmap(null);
+ final float shiftFactor = AdaptiveIconDrawable.getExtraInsetFraction() / sizeScaleFactor;
+ final float previewShiftX = shiftFactor * previewWidth;
+ final float previewShiftY = shiftFactor * previewHeight;
+
+ Bitmap previewBitmap = UiFactory.createFromRenderer(previewWidth, previewHeight, false,
+ (canvas) -> {
+ int count = canvas.save();
+ canvas.translate(previewShiftX, previewShiftY);
+ icon.getPreviewItemManager().draw(canvas);
+ canvas.restoreToCount(count);
+ });
// Initialize mask
Path mask = new Path();
diff --git a/src/com/android/launcher3/graphics/BitmapRenderer.java b/src/com/android/launcher3/graphics/BitmapRenderer.java
new file mode 100644
index 0000000..4652ded
--- /dev/null
+++ b/src/com/android/launcher3/graphics/BitmapRenderer.java
@@ -0,0 +1,23 @@
+/*
+ * 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.graphics;
+
+import android.graphics.Canvas;
+
+public interface BitmapRenderer {
+
+ void render(Canvas out);
+}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 355c231..902906f 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -35,6 +35,7 @@
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.UiThreadHelper;
import java.nio.ByteBuffer;
@@ -77,8 +78,10 @@
/**
* Draws the {@link #mView} into the given {@param destCanvas}.
*/
- private void drawDragView(Canvas destCanvas) {
+ private void drawDragView(Canvas destCanvas, float scale) {
destCanvas.save();
+ destCanvas.scale(scale, scale);
+
if (mView instanceof BubbleTextView) {
Drawable d = ((BubbleTextView) mView).getIcon();
Rect bounds = getDrawableBounds(d);
@@ -120,6 +123,7 @@
int width = mView.getWidth();
int height = mView.getHeight();
+ boolean forceSoftwareRenderer = false;
if (mView instanceof BubbleTextView) {
Drawable d = ((BubbleTextView) mView).getIcon();
Rect bounds = getDrawableBounds(d);
@@ -129,20 +133,14 @@
scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
width = (int) (mView.getWidth() * scale);
height = (int) (mView.getHeight() * scale);
+
+ // Use software renderer for widgets as we know that they already work
+ forceSoftwareRenderer = true;
}
- Bitmap b = Bitmap.createBitmap(width + blurSizeOutline, height + blurSizeOutline,
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(b);
-
- canvas.save();
- canvas.scale(scale, scale);
- drawDragView(canvas);
- canvas.restore();
-
- canvas.setBitmap(null);
-
- return b;
+ final float scaleFinal = scale;
+ return UiFactory.createFromRenderer(width + blurSizeOutline, height + blurSizeOutline,
+ forceSoftwareRenderer, (c) -> drawDragView(c, scaleFinal));
}
public final void generateDragOutline(Bitmap preview) {
diff --git a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
index fdf2d67..ebfe1e7 100644
--- a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
@@ -33,6 +33,7 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.R;
+import com.android.launcher3.uioverrides.UiFactory;
/**
* Utility class to generate shadow and outline effect, which are used for click feedback
@@ -106,7 +107,11 @@
int saveCount = mCanvas.save();
mCanvas.scale(scaleX, scaleY);
mCanvas.translate(-rect.left, -rect.top);
- drawable.draw(mCanvas);
+ if (!UiFactory.USE_HARDWARE_BITMAP) {
+ // TODO: Outline generation requires alpha extraction, which is costly for
+ // hardware bitmaps. Instead use canvas layer operations once its available.
+ drawable.draw(mCanvas);
+ }
mCanvas.restoreToCount(saveCount);
mCanvas.setBitmap(null);
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 1eddb2c..8c4738c 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -49,6 +49,7 @@
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.util.Provider;
/**
@@ -132,7 +133,12 @@
Bitmap bitmap = createIconBitmap(icon, context, scale);
if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.ATLEAST_OREO &&
icon instanceof AdaptiveIconDrawable) {
- bitmap = ShadowGenerator.getInstance(context).recreateIcon(bitmap);
+ synchronized (sCanvas) {
+ sCanvas.setBitmap(bitmap);
+ ShadowGenerator.getInstance(context).recreateIcon(
+ Bitmap.createBitmap(bitmap), sCanvas);
+ sCanvas.setBitmap(null);
+ }
}
if (user != null && !Process.myUserHandle().equals(user)) {
@@ -183,16 +189,25 @@
return createIconBitmap(icon, context, scale);
}
- public static Bitmap badgeWithDrawable(Bitmap srcTgt, Drawable badge, Context context) {
- int badgeSize = context.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
+ /**
+ * Adds the {@param badge} on top of {@param target} using the badge dimensions.
+ */
+ public static void badgeWithDrawable(Bitmap target, Drawable badge, Context context) {
synchronized (sCanvas) {
- sCanvas.setBitmap(srcTgt);
- int iconSize = srcTgt.getWidth();
- badge.setBounds(iconSize - badgeSize, iconSize - badgeSize, iconSize, iconSize);
- badge.draw(sCanvas);
+ sCanvas.setBitmap(target);
+ badgeWithDrawable(sCanvas, badge, context);
sCanvas.setBitmap(null);
}
- return srcTgt;
+ }
+
+ /**
+ * Adds the {@param badge} on top of {@param target} using the badge dimensions.
+ */
+ private static void badgeWithDrawable(Canvas target, Drawable badge, Context context) {
+ int badgeSize = context.getResources().getDimensionPixelSize(R.dimen.profile_badge_size);
+ int iconSize = LauncherAppState.getIDP(context).iconBitmapSize;
+ badge.setBounds(iconSize - badgeSize, iconSize - badgeSize, iconSize, iconSize);
+ badge.draw(target);
}
/**
@@ -326,9 +341,16 @@
if (!badged) {
return unbadgedBitmap;
}
- unbadgedBitmap = ShadowGenerator.getInstance(context).recreateIcon(unbadgedBitmap);
- return badgeWithDrawable(unbadgedBitmap,
- new FastBitmapDrawable(getShortcutInfoBadge(shortcutInfo, cache)), context);
+
+ int size = app.getInvariantDeviceProfile().iconBitmapSize;
+
+ final Bitmap unbadgedfinal = unbadgedBitmap;
+ final Bitmap badge = getShortcutInfoBadge(shortcutInfo, cache);
+
+ return UiFactory.createFromRenderer(size, size, false, (c) -> {
+ ShadowGenerator.getInstance(context).recreateIcon(unbadgedfinal, c);
+ badgeWithDrawable(c, new FastBitmapDrawable(badge), context);
+ });
}
public static Bitmap getShortcutInfoBadge(ShortcutInfoCompat shortcutInfo, IconCache cache) {
diff --git a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
new file mode 100644
index 0000000..6df1ecb
--- /dev/null
+++ b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
@@ -0,0 +1,71 @@
+/*
+ * 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.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+/**
+ * Utility class which draws a bitmap by dissecting it into 3 segments and stretching
+ * the middle segment.
+ */
+public class NinePatchDrawHelper {
+
+ // The extra width used for the bitmap. This portion of the bitmap is stretched to match the
+ // width of the draw region. Randomly chosen, any value > 4 will be sufficient.
+ public static final int EXTENSION_PX = 20;
+
+ private final Rect mSrc = new Rect();
+ private final RectF mDst = new RectF();
+ public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ public void draw(Bitmap bitmap, Canvas canvas, float left, float top, float right) {
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+
+ mSrc.top = 0;
+ mSrc.bottom = height;
+
+ mDst.top = top;
+ mDst.bottom = top + height;
+
+ int halfWidth = width / 2;
+
+ // Draw left edge
+ drawRegion(bitmap, canvas, 0, halfWidth, left, left + halfWidth);
+
+ // Draw right edge
+ drawRegion(bitmap, canvas, halfWidth, width, right - halfWidth, right);
+
+ // Draw middle stretched region
+ int halfExt = EXTENSION_PX / 4;
+ drawRegion(bitmap, canvas, halfWidth - halfExt, halfWidth + halfExt,
+ left + halfWidth, right - halfWidth);
+ }
+
+ private void drawRegion(Bitmap bitmap, Canvas c,
+ int srcLeft, int srcRight, float dstLeft, float dstRight) {
+ mSrc.left = srcLeft;
+ mSrc.right = srcRight;
+
+ mDst.left = dstLeft;
+ mDst.right = dstRight;
+ c.drawBitmap(bitmap, mSrc, mDst, paint);
+ }
+}
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index 60eeef5..96f2629 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -24,6 +24,8 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.v4.graphics.ColorUtils;
@@ -50,49 +52,38 @@
private final int mIconSize;
- private final Canvas mCanvas;
private final Paint mBlurPaint;
private final Paint mDrawPaint;
private final BlurMaskFilter mDefaultBlurMaskFilter;
private ShadowGenerator(Context context) {
mIconSize = LauncherAppState.getIDP(context).iconBitmapSize;
- mCanvas = new Canvas();
mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mDefaultBlurMaskFilter = new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL);
}
- public synchronized Bitmap recreateIcon(Bitmap icon) {
- return recreateIcon(icon, true, mDefaultBlurMaskFilter, AMBIENT_SHADOW_ALPHA,
- KEY_SHADOW_ALPHA);
+ public synchronized void recreateIcon(Bitmap icon, Canvas out) {
+ recreateIcon(icon, mDefaultBlurMaskFilter, AMBIENT_SHADOW_ALPHA, KEY_SHADOW_ALPHA, out);
}
- public synchronized Bitmap recreateIcon(Bitmap icon, boolean resize,
- BlurMaskFilter blurMaskFilter, int ambientAlpha, int keyAlpha) {
- int width = resize ? mIconSize : icon.getWidth();
- int height = resize ? mIconSize : icon.getHeight();
+ public synchronized void recreateIcon(Bitmap icon, BlurMaskFilter blurMaskFilter,
+ int ambientAlpha, int keyAlpha, Canvas out) {
int[] offset = new int[2];
-
mBlurPaint.setMaskFilter(blurMaskFilter);
Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
- Bitmap result = Bitmap.createBitmap(width, height, Config.ARGB_8888);
- mCanvas.setBitmap(result);
// Draw ambient shadow
mDrawPaint.setAlpha(ambientAlpha);
- mCanvas.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
+ out.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
// Draw key shadow
mDrawPaint.setAlpha(keyAlpha);
- mCanvas.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint);
+ out.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint);
// Draw the icon
mDrawPaint.setAlpha(255);
- mCanvas.drawBitmap(icon, 0, 0, mDrawPaint);
-
- mCanvas.setBitmap(null);
- return result;
+ out.drawBitmap(icon, 0, 0, mDrawPaint);
}
public static ShadowGenerator getInstance(Context context) {
@@ -178,6 +169,18 @@
p.setShadowLayer(shadowBlur, 0, 0,
ColorUtils.setAlphaComponent(Color.BLACK, ambientShadowAlpha));
c.drawRoundRect(bounds, radius, radius, p);
+
+ if (Color.alpha(color) < 255) {
+ // Clear any content inside the pill-rect for translucent fill.
+ p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ p.clearShadowLayer();
+ p.setColor(Color.BLACK);
+ c.drawRoundRect(bounds, radius, radius, p);
+
+ p.setXfermode(null);
+ p.setColor(color);
+ c.drawRoundRect(bounds, radius, radius, p);
+ }
}
}
}
diff --git a/src/com/android/launcher3/views/AllAppsScrim.java b/src/com/android/launcher3/views/AllAppsScrim.java
new file mode 100644
index 0000000..1ada251
--- /dev/null
+++ b/src/com/android/launcher3/views/AllAppsScrim.java
@@ -0,0 +1,150 @@
+/*
+ * 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.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.support.v4.graphics.ColorUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
+import com.android.launcher3.graphics.NinePatchDrawHelper;
+import com.android.launcher3.graphics.ShadowGenerator;
+import com.android.launcher3.util.Themes;
+
+import static com.android.launcher3.graphics.NinePatchDrawHelper.EXTENSION_PX;
+
+public class AllAppsScrim extends View implements WallpaperColorInfo.OnChangeListener {
+
+ private static final int MAX_ALPHA = 235;
+ private static final int MIN_ALPHA_PORTRAIT = 100;
+ private static final int MIN_ALPHA_LANDSCAPE = MAX_ALPHA;
+
+ private final WallpaperColorInfo mWallpaperColorInfo;
+ private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ private final float mRadius;
+ private final int mMinAlpha;
+ private final int mAlphaRange;
+ private final int mScrimColor;
+
+ private final float mShadowBlur;
+ private final Bitmap mShadowBitmap;
+
+ private final NinePatchDrawHelper mShadowHelper = new NinePatchDrawHelper();
+
+ private int mFillAlpha;
+
+ private float mDrawHeight;
+ private float mTranslateY;
+
+ public AllAppsScrim(Context context) {
+ this(context, null);
+ }
+
+ public AllAppsScrim(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AllAppsScrim(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ mWallpaperColorInfo = WallpaperColorInfo.getInstance(context);
+ mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
+ mRadius = getResources().getDimension(R.dimen.all_apps_scrim_radius);
+ mShadowBlur = getResources().getDimension(R.dimen.all_apps_scrim_blur);
+
+ Launcher launcher = Launcher.getLauncher(context);
+ mFillAlpha = mMinAlpha = launcher.getDeviceProfile().isVerticalBarLayout()
+ ? MIN_ALPHA_LANDSCAPE : MIN_ALPHA_PORTRAIT;
+ mAlphaRange = MAX_ALPHA - mMinAlpha;
+ mShadowBitmap = generateShadowBitmap();
+
+ updateColors(mWallpaperColorInfo);
+ }
+
+ private Bitmap generateShadowBitmap() {
+ float curveBot = mRadius + mShadowBlur;
+
+ ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
+ builder.radius = mRadius;
+ builder.shadowBlur = mShadowBlur;
+
+ // Create the bitmap such that only the top half is drawn in the bitmap.
+ int bitmapHeight = Math.round(curveBot);
+ int bitmapWidth = bitmapHeight + EXTENSION_PX;
+ Bitmap result = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
+
+ builder.bounds.set(0, mShadowBlur, bitmapWidth, 2 * curveBot + EXTENSION_PX);
+ builder.drawShadow(new Canvas(result));
+ return result;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mWallpaperColorInfo.addOnChangeListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mWallpaperColorInfo.removeOnChangeListener(this);
+ }
+
+ @Override
+ public void onExtractedColorsChanged(WallpaperColorInfo info) {
+ updateColors(info);
+ invalidate();
+ }
+
+ private void updateColors(WallpaperColorInfo info) {
+ mFillPaint.setColor(ColorUtils.compositeColors(mScrimColor,
+ ColorUtils.compositeColors(mScrimColor, info.getMainColor())));
+ mFillPaint.setAlpha(mFillAlpha);
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ float edgeTop = getHeight() + mTranslateY - mDrawHeight;
+
+ mShadowHelper.draw(mShadowBitmap, canvas, 0, edgeTop - mShadowBlur, getWidth());
+ canvas.drawRoundRect(0, edgeTop, getWidth(),
+ getHeight() + mRadius, mRadius, mRadius, mFillPaint);
+ }
+
+ public void setProgress(float translateY, float alpha) {
+ mFillAlpha = Math.round(alpha * mAlphaRange + mMinAlpha);
+ mFillPaint.setAlpha(mFillAlpha);
+
+ mTranslateY = translateY;
+
+ invalidate();
+ }
+
+ public void setDrawRegion(float height) {
+ mDrawHeight = height;
+ }
+}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 2e29015..fc81e80 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -18,14 +18,19 @@
import static com.android.launcher3.LauncherState.OVERVIEW;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.view.View.AccessibilityDelegate;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.graphics.BitmapRenderer;
import com.android.launcher3.util.TouchController;
public class UiFactory {
+ public static final boolean USE_HARDWARE_BITMAP = false;
+
public static TouchController[] createTouchControllers(Launcher launcher) {
return new TouchController[] {
new AllAppsSwipeController(launcher), new PinchToOverviewListener(launcher)};
@@ -44,4 +49,11 @@
public static void onWorkspaceLongPress(Launcher launcher) {
launcher.getStateManager().goToState(OVERVIEW);
}
+
+ public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer,
+ BitmapRenderer renderer) {
+ Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ renderer.render(new Canvas(result));
+ return result;
+ }
}