Merge "Launcher dump proto that will be used for:" into ub-launcher3-master
diff --git a/res/drawable/bg_pill_focused.xml b/res/drawable/bg_pill_focused.xml
deleted file mode 100644
index 54075d9..0000000
--- a/res/drawable/bg_pill_focused.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true">
- <shape android:shape="rectangle">
- <stroke android:color="?android:attr/colorControlActivated" android:width="2dp" />
- <corners android:radius="@dimen/bg_pill_radius" />
- </shape>
- </item>
-</selector>
\ No newline at end of file
diff --git a/res/drawable/bg_white_pill.xml b/res/drawable/bg_white_pill.xml
deleted file mode 100644
index f92f739..0000000
--- a/res/drawable/bg_white_pill.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="#FFFFFF" />
- <corners android:radius="@dimen/bg_pill_radius" />
-</shape>
\ No newline at end of file
diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml
index 6c1d4da..b2ed709 100644
--- a/res/layout/deep_shortcut.xml
+++ b/res/layout/deep_shortcut.xml
@@ -17,18 +17,16 @@
<com.android.launcher3.shortcuts.DeepShortcutView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="@dimen/bg_pill_width"
- android:layout_height="@dimen/bg_pill_height"
- android:elevation="@dimen/deep_shortcuts_elevation"
- android:background="@drawable/bg_white_pill" >
+ android:layout_width="@dimen/bg_popup_item_width"
+ android:layout_height="@dimen/bg_popup_item_height" >
<com.android.launcher3.shortcuts.DeepShortcutTextView
style="@style/BaseIcon"
android:id="@+id/deep_shortcut"
- android:background="@drawable/bg_pill_focused"
+ android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
android:textAlignment="viewStart"
- android:paddingStart="@dimen/bg_pill_height"
+ android:paddingStart="@dimen/bg_popup_item_height"
android:paddingEnd="@dimen/deep_shortcut_padding_end"
android:drawableEnd="@drawable/deep_shortcuts_drag_handle"
android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
@@ -40,10 +38,18 @@
android:elevation="@dimen/deep_shortcuts_elevation" />
<View
- android:id="@+id/popup_item_icon"
+ android:id="@+id/icon"
android:layout_width="@dimen/deep_shortcut_icon_size"
android:layout_height="@dimen/deep_shortcut_icon_size"
android:layout_margin="@dimen/deep_shortcut_padding_start"
android:layout_gravity="start" />
+ <View
+ android:id="@+id/divider"
+ android:layout_width="@dimen/deep_shortcuts_divider_width"
+ android:layout_height="@dimen/popup_item_divider_height"
+ android:layout_gravity="end|bottom"
+ android:visibility="gone"
+ android:background="?android:attr/listDivider" />
+
</com.android.launcher3.shortcuts.DeepShortcutView>
diff --git a/res/layout/notification.xml b/res/layout/notification.xml
index 48c7b48..e148cbb 100644
--- a/res/layout/notification.xml
+++ b/res/layout/notification.xml
@@ -17,7 +17,7 @@
<com.android.launcher3.notification.NotificationItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notification_view"
- android:layout_width="@dimen/bg_pill_width"
+ android:layout_width="@dimen/bg_popup_item_width"
android:layout_height="wrap_content"
android:elevation="@dimen/deep_shortcuts_elevation"
android:background="@drawable/bg_white_round_rect">
diff --git a/res/layout/notification_footer.xml b/res/layout/notification_footer.xml
index c025819..5428208 100644
--- a/res/layout/notification_footer.xml
+++ b/res/layout/notification_footer.xml
@@ -26,7 +26,7 @@
<View
android:id="@+id/divider"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_divider_height"/>
+ android:layout_height="@dimen/popup_item_divider_height"/>
<LinearLayout
android:id="@+id/icon_row"
diff --git a/res/layout/shortcuts_item.xml b/res/layout/shortcuts_item.xml
new file mode 100644
index 0000000..8b20bcb
--- /dev/null
+++ b/res/layout/shortcuts_item.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<com.android.launcher3.shortcuts.ShortcutsItemView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/shortcuts_view"
+ android:layout_width="@dimen/bg_popup_item_width"
+ android:layout_height="wrap_content"
+ android:elevation="@dimen/deep_shortcuts_elevation"
+ android:background="@drawable/bg_white_round_rect">
+
+ <LinearLayout
+ android:id="@+id/deep_shortcuts"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ </LinearLayout>
+
+</com.android.launcher3.shortcuts.ShortcutsItemView>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 177e08e..8fee26b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -150,10 +150,9 @@
<!-- Deep shortcuts -->
<dimen name="deep_shortcuts_elevation">9dp</dimen>
- <dimen name="bg_pill_width">208dp</dimen>
- <dimen name="bg_pill_height">48dp</dimen>
- <dimen name="bg_pill_radius">24dp</dimen>
- <dimen name="deep_shortcuts_spacing">4dp</dimen>
+ <dimen name="bg_popup_item_width">208dp</dimen>
+ <dimen name="bg_popup_item_height">48dp</dimen>
+ <dimen name="popup_items_spacing">4dp</dimen>
<dimen name="pre_drag_view_scale">6dp</dimen>
<!-- an icon with shortcuts must be dragged this far before the container is removed. -->
<dimen name="deep_shortcuts_start_drag_threshold">16dp</dimen>
@@ -171,6 +170,8 @@
deep_shortcut_padding_end + deep_shortcut_drag_handle_size / 2 - deep_shortcuts_arrow_width / 2
also happens to equal 19dp-->
<dimen name="deep_shortcuts_arrow_horizontal_offset">19dp</dimen>
+ <!-- popup_item_width - icon_size - padding_start - drawable_padding -->
+ <dimen name="deep_shortcuts_divider_width">158dp</dimen>
<!-- Icon badges (with notification counts) -->
<dimen name="badge_size">24dp</dimen>
@@ -186,9 +187,9 @@
<!-- (icon_size - footer_icon_size) / 2 -->
<dimen name="notification_footer_icon_row_padding">2dp</dimen>
<dimen name="notification_main_height">60dp</dimen>
- <dimen name="notification_footer_height">@dimen/bg_pill_height</dimen>
+ <dimen name="notification_footer_height">@dimen/bg_popup_item_height</dimen>
<dimen name="notification_elevation">2dp</dimen>
- <dimen name="notification_divider_height">0.5dp</dimen>
+ <dimen name="popup_item_divider_height">0.5dp</dimen>
<dimen name="swipe_helper_falsing_threshold">70dp</dimen>
<!-- Other -->
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 52a83dc..bd12686 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -95,7 +95,7 @@
return null;
}
- protected static void closeOpenContainer(Launcher launcher, @FloatingViewType int type) {
+ public static void closeOpenContainer(Launcher launcher, @FloatingViewType int type) {
AbstractFloatingView view = getOpenView(launcher, type);
if (view != null) {
view.close(true);
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 107d700..af64b87 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -40,6 +40,7 @@
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.badge.BadgeRenderer;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.FolderIconPreviewVerifier;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.HolographicOutlineHelper;
import com.android.launcher3.graphics.IconPalette;
@@ -548,7 +549,9 @@
applyFromApplicationInfo((AppInfo) info);
} else if (info instanceof ShortcutInfo) {
applyFromShortcutInfo((ShortcutInfo) info);
- if ((info.rank < FolderIcon.NUM_ITEMS_IN_PREVIEW) && (info.container >= 0)) {
+ FolderIconPreviewVerifier verifier =
+ new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
+ if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
View folderIcon =
mLauncher.getWorkspace().getHomescreenIconByItemId(info.container);
if (folderIcon != null) {
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 8d69fe3..8a477d8 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -42,6 +42,7 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
/**
@@ -142,8 +143,8 @@
mCurrentFilter = new ColorMatrix();
}
- DragView.setColorScale(getTextColor(), mSrcFilter);
- DragView.setColorScale(targetColor, mDstFilter);
+ Themes.setColorScaleOnMatrix(getTextColor(), mSrcFilter);
+ Themes.setColorScaleOnMatrix(targetColor, mDstFilter);
ValueAnimator anim1 = ValueAnimator.ofObject(
new FloatArrayEvaluator(mCurrentFilter.getArray()),
mSrcFilter.getArray(), mDstFilter.getArray());
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 6a78367..384f202 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -889,6 +889,8 @@
Intent intent;
String targetPkg;
+ FolderIconPreviewVerifier verifier =
+ new FolderIconPreviewVerifier(mApp.getInvariantDeviceProfile());
while (!mStopped && c.moveToNext()) {
try {
if (c.user == null) {
@@ -987,7 +989,7 @@
c.markDeleted("Unrestored app removed: " + targetPkg);
continue;
}
- } else if (pmHelper.isAppOnSdcard(targetPkg)) {
+ } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
// Package is present but not available.
disabledState |= ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
// Add the icon on the workspace anyway.
@@ -1013,7 +1015,7 @@
}
boolean useLowResIcon = !c.isOnWorkspaceOrHotseat() &&
- c.getInt(rankIndex) >= FolderIcon.NUM_ITEMS_IN_PREVIEW;
+ !verifier.isItemInPreview(c.getInt(rankIndex));
if (c.restoreFlag != 0) {
// Already verified above that user is same as default user
@@ -1038,8 +1040,7 @@
info.iconBitmap = LauncherIcons
.createShortcutIcon(pinnedShortcut, context);
if (pmHelper.isAppSuspended(
- info.getTargetComponent().getPackageName(),
- info.user)) {
+ pinnedShortcut.getPackage(), info.user)) {
info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
}
intent = info.intent;
@@ -1052,7 +1053,7 @@
info = c.loadSimpleShortcut();
// Shortcuts are only available on the primary profile
- if (pmHelper.isAppSuspended(targetPkg)) {
+ if (pmHelper.isAppSuspended(targetPkg, c.user)) {
disabledState |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
}
diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java
index 864a65d..5896928 100644
--- a/src/com/android/launcher3/badge/BadgeRenderer.java
+++ b/src/com/android/launcher3/badge/BadgeRenderer.java
@@ -20,14 +20,15 @@
import android.content.res.Resources;
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.graphics.Shader;
import android.support.annotation.Nullable;
import com.android.launcher3.R;
import com.android.launcher3.graphics.IconPalette;
+import com.android.launcher3.graphics.ShadowGenerator;
/**
* Contains parameters necessary to draw a badge for an icon (e.g. the size of the badge).
@@ -40,10 +41,12 @@
private final int mTextHeight;
private final IconDrawer mLargeIconDrawer;
private final IconDrawer mSmallIconDrawer;
- private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG
+ | Paint.FILTER_BITMAP_FLAG);
+ private final Bitmap mBackgroundWithShadow;
- public BadgeRenderer(Context context) {
+ public BadgeRenderer(final Context context) {
mContext = context;
Resources res = context.getResources();
mSize = res.getDimensionPixelSize(R.dimen.badge_size);
@@ -56,6 +59,8 @@
Rect tempTextHeight = new Rect();
mTextPaint.getTextBounds("0", 0, 1, tempTextHeight);
mTextHeight = tempTextHeight.height();
+
+ mBackgroundWithShadow = ShadowGenerator.createCircleWithShadow(Color.WHITE, mSize);
}
/**
@@ -68,13 +73,15 @@
*/
public void draw(Canvas canvas, IconPalette palette, @Nullable BadgeInfo badgeInfo,
Rect iconBounds, float badgeScale) {
- mBackgroundPaint.setColor(palette.backgroundColor);
mTextPaint.setColor(palette.textColor);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
// We draw the badge relative to its center.
canvas.translate(iconBounds.right - mSize / 2, iconBounds.top + mSize / 2);
canvas.scale(badgeScale, badgeScale);
- canvas.drawCircle(0, 0, mSize / 2, mBackgroundPaint);
+ mBackgroundPaint.setColorFilter(palette.backgroundColorMatrixFilter);
+ int backgroundSize = mBackgroundWithShadow.getHeight(); // Same as width.
+ canvas.drawBitmap(mBackgroundWithShadow, -backgroundSize / 2, -backgroundSize / 2,
+ mBackgroundPaint);
IconDrawer iconDrawer = badgeInfo != null && badgeInfo.isIconLarge()
? mLargeIconDrawer : mSmallIconDrawer;
Shader icon = badgeInfo == null ? null : badgeInfo.getNotificationIconForBadge(
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 44a3686..2eb5b02 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -73,7 +73,8 @@
UserHandle user);
public abstract void startActivityForProfile(ComponentName component, UserHandle user,
Rect sourceBounds, Bundle opts);
- public abstract ApplicationInfo getApplicationInfo(String packageName, UserHandle user);
+ public abstract ApplicationInfo getApplicationInfo(
+ String packageName, int flags, UserHandle user);
public abstract void showAppDetailsForProfile(ComponentName component, UserHandle user);
public abstract void addOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
public abstract void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index 776f593..e5517a6 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -27,6 +27,7 @@
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.Process;
import android.os.UserHandle;
import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL;
@@ -66,9 +67,28 @@
}
@Override
- public ApplicationInfo getApplicationInfo(String packageName, UserHandle user) {
- List<LauncherActivityInfo> activityList = mLauncherApps.getActivityList(packageName, user);
- return activityList.size() > 0 ? activityList.get(0).getApplicationInfo() : null;
+ public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) {
+ final boolean isPrimaryUser = Process.myUserHandle().equals(user);
+ if (!isPrimaryUser && (flags == 0)) {
+ // We are looking for an installed app on a secondary profile. Prior to O, the only
+ // entry point for work profiles is through the LauncherActivity.
+ List<LauncherActivityInfo> activityList =
+ mLauncherApps.getActivityList(packageName, user);
+ return activityList.size() > 0 ? activityList.get(0).getApplicationInfo() : null;
+ }
+ try {
+ ApplicationInfo info =
+ mContext.getPackageManager().getApplicationInfo(packageName, flags);
+ // There is no way to check if the app is installed for managed profile. But for
+ // primary profile, we can still have this check.
+ if (isPrimaryUser && ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
+ return null;
+ }
+ return info;
+ } catch (PackageManager.NameNotFoundException e) {
+ // Package not found
+ return null;
+ }
}
@Override
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
index 377907a..c0f80d0 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
@@ -35,8 +35,9 @@
}
@Override
- public ApplicationInfo getApplicationInfo(String packageName, UserHandle user) {
- return mLauncherApps.getApplicationInfo(packageName, 0, user);
+ public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) {
+ ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user);
+ return info == null || (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 ? null : info;
}
@Override
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index e4c9be4..7806c98 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -24,7 +24,6 @@
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
@@ -36,6 +35,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
import java.util.Arrays;
@@ -259,7 +259,7 @@
m1.setSaturation(0);
ColorMatrix m2 = new ColorMatrix();
- setColorScale(color, m2);
+ Themes.setColorScaleOnMatrix(color, m2);
m1.postConcat(m2);
animateFilterTo(m1.getArray());
@@ -384,11 +384,6 @@
}
}
- public static void setColorScale(int color, ColorMatrix target) {
- target.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
- Color.blue(color) / 255f, Color.alpha(color) / 255f);
- }
-
public int getBlurSizeOutline() {
return mBlurSizeOutline;
}
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index 194a62f..503c2ec 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -121,6 +121,11 @@
}
@Override
+ public float getIconSize() {
+ return mIconSize;
+ }
+
+ @Override
public int maxNumItems() {
return MAX_NUM_ITEMS_IN_PREVIEW;
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 3d2ffb4..763ab96 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -66,6 +66,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
+import com.android.launcher3.anim.AnimationLayerSet;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dragndrop.DragController;
@@ -510,6 +511,58 @@
mState = STATE_SMALL;
}
+ private AnimatorSet getOpeningAnimatorSet() {
+ AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+
+ int width = getFolderWidth();
+ int height = getFolderHeight();
+
+ float transX = - 0.075f * (width / 2 - getPivotX());
+ float transY = - 0.075f * (height / 2 - getPivotY());
+ setTranslationX(transX);
+ setTranslationY(transY);
+ PropertyValuesHolder tx = PropertyValuesHolder.ofFloat(TRANSLATION_X, transX, 0);
+ PropertyValuesHolder ty = PropertyValuesHolder.ofFloat(TRANSLATION_Y, transY, 0);
+
+ Animator drift = ObjectAnimator.ofPropertyValuesHolder(this, tx, ty);
+ drift.setDuration(mMaterialExpandDuration);
+ drift.setStartDelay(mMaterialExpandStagger);
+ drift.setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+ int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
+ int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
+ float radius = (float) Math.hypot(rx, ry);
+
+ Animator reveal = new CircleRevealOutlineProvider((int) getPivotX(),
+ (int) getPivotY(), 0, radius).createRevealAnimator(this);
+ reveal.setDuration(mMaterialExpandDuration);
+ reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+ mContent.setAlpha(0f);
+ Animator iconsAlpha = ObjectAnimator.ofFloat(mContent, "alpha", 0f, 1f);
+ iconsAlpha.setDuration(mMaterialExpandDuration);
+ iconsAlpha.setStartDelay(mMaterialExpandStagger);
+ iconsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
+
+ mFooter.setAlpha(0f);
+ Animator textAlpha = ObjectAnimator.ofFloat(mFooter, "alpha", 0f, 1f);
+ textAlpha.setDuration(mMaterialExpandDuration);
+ textAlpha.setStartDelay(mMaterialExpandStagger);
+ textAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
+
+ anim.play(drift);
+ anim.play(iconsAlpha);
+ anim.play(textAlpha);
+ anim.play(reveal);
+
+ AnimationLayerSet layerSet = new AnimationLayerSet();
+ layerSet.addView(mContent);
+ layerSet.addView(mFooter);
+ anim.addListener(layerSet);
+
+ return anim;
+ }
+
/**
* Opens the user folder described by the specified tag. The opening of the folder
* is animated relative to the specified View. If the View is null, no animation
@@ -554,55 +607,10 @@
mFolderIcon.growAndFadeOut();
- AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
- int width = getFolderWidth();
- int height = getFolderHeight();
-
- float transX = - 0.075f * (width / 2 - getPivotX());
- float transY = - 0.075f * (height / 2 - getPivotY());
- setTranslationX(transX);
- setTranslationY(transY);
- PropertyValuesHolder tx = PropertyValuesHolder.ofFloat(TRANSLATION_X, transX, 0);
- PropertyValuesHolder ty = PropertyValuesHolder.ofFloat(TRANSLATION_Y, transY, 0);
-
- Animator drift = ObjectAnimator.ofPropertyValuesHolder(this, tx, ty);
- drift.setDuration(mMaterialExpandDuration);
- drift.setStartDelay(mMaterialExpandStagger);
- drift.setInterpolator(new LogDecelerateInterpolator(100, 0));
-
- int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
- int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
- float radius = (float) Math.hypot(rx, ry);
-
- Animator reveal = new CircleRevealOutlineProvider((int) getPivotX(),
- (int) getPivotY(), 0, radius).createRevealAnimator(this);
- reveal.setDuration(mMaterialExpandDuration);
- reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
-
- mContent.setAlpha(0f);
- Animator iconsAlpha = ObjectAnimator.ofFloat(mContent, "alpha", 0f, 1f);
- iconsAlpha.setDuration(mMaterialExpandDuration);
- iconsAlpha.setStartDelay(mMaterialExpandStagger);
- iconsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
-
- mFooter.setAlpha(0f);
- Animator textAlpha = ObjectAnimator.ofFloat(mFooter, "alpha", 0f, 1f);
- textAlpha.setDuration(mMaterialExpandDuration);
- textAlpha.setStartDelay(mMaterialExpandStagger);
- textAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
-
- anim.play(drift);
- anim.play(iconsAlpha);
- anim.play(textAlpha);
- anim.play(reveal);
-
- mContent.setLayerType(LAYER_TYPE_HARDWARE, null);
- mFooter.setLayerType(LAYER_TYPE_HARDWARE, null);
+ AnimatorSet anim = getOpeningAnimatorSet();
onCompleteRunnable = new Runnable() {
@Override
public void run() {
- mContent.setLayerType(LAYER_TYPE_NONE, null);
- mFooter.setLayerType(LAYER_TYPE_NONE, null);
mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
}
};
@@ -715,12 +723,22 @@
parent.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
+ private AnimatorSet getClosingAnimatorSet() {
+ AnimatorSet animatorSet = LauncherAnimUtils.createAnimatorSet();
+ animatorSet.play(LauncherAnimUtils.ofViewAlphaAndScale(this, 0, 0.9f, 0.9f));
+
+ AnimationLayerSet layerSet = new AnimationLayerSet();
+ layerSet.addView(this);
+ animatorSet.addListener(layerSet);
+
+ return animatorSet;
+ }
+
private void animateClosed() {
- final ObjectAnimator oa = LauncherAnimUtils.ofViewAlphaAndScale(this, 0, 0.9f, 0.9f);
- oa.addListener(new AnimatorListenerAdapter() {
+ AnimatorSet a = getClosingAnimatorSet();
+ a.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- setLayerType(LAYER_TYPE_NONE, null);
closeComplete(true);
}
@Override
@@ -732,9 +750,8 @@
mState = STATE_ANIMATING;
}
});
- oa.setDuration(mExpandDuration);
- setLayerType(LAYER_TYPE_HARDWARE, null);
- oa.start();
+ a.setDuration(mExpandDuration);
+ a.start();
}
private void closeComplete(boolean wasAnimated) {
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 407f923..d84a9d2 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -1138,6 +1138,7 @@
PreviewItemDrawingParams params);
void init(int availableSpace, int intrinsicIconSize, boolean rtl);
float scaleForItem(int index, int totalNumItems);
+ float getIconSize();
int maxNumItems();
boolean clipToBackground();
}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index f29fb9a..bc78324 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -331,6 +331,8 @@
int position = 0;
int newX, newY, rank;
+ FolderIconPreviewVerifier verifier = new FolderIconPreviewVerifier(
+ Launcher.getLauncher(getContext()).getDeviceProfile().inv);
rank = 0;
for (int i = 0; i < itemCount; i++) {
View v = list.size() > i ? list.get(i) : null;
@@ -363,7 +365,7 @@
currentPage.addViewToCellLayout(
v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
- if (rank < FolderIcon.NUM_ITEMS_IN_PREVIEW && v instanceof BubbleTextView) {
+ if (verifier.isItemInPreview(rank) && v instanceof BubbleTextView) {
((BubbleTextView) v).verifyHighRes();
}
}
diff --git a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
index 1f4e648..9c8c2ef 100644
--- a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
@@ -87,6 +87,11 @@
}
@Override
+ public float getIconSize() {
+ return mBaselineIconSize;
+ }
+
+ @Override
public float scaleForItem(int index, int numItems) {
// Scale is determined by the position of the icon in the preview.
index = MAX_NUM_ITEMS_IN_PREVIEW - index - 1;
diff --git a/src/com/android/launcher3/graphics/IconPalette.java b/src/com/android/launcher3/graphics/IconPalette.java
index 23c6a12..cd7cf70 100644
--- a/src/com/android/launcher3/graphics/IconPalette.java
+++ b/src/com/android/launcher3/graphics/IconPalette.java
@@ -19,11 +19,12 @@
import android.app.Notification;
import android.content.Context;
import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.Themes;
/**
@@ -41,12 +42,16 @@
public final int dominantColor;
public final int backgroundColor;
+ public final ColorMatrixColorFilter backgroundColorMatrixFilter;
public final int textColor;
public final int secondaryColor;
private IconPalette(int color) {
dominantColor = color;
backgroundColor = getMutedColor(dominantColor);
+ ColorMatrix backgroundColorMatrix = new ColorMatrix();
+ Themes.setColorScaleOnMatrix(backgroundColor, backgroundColorMatrix);
+ backgroundColorMatrixFilter = new ColorMatrixColorFilter(backgroundColorMatrix);
textColor = getTextColorForBackground(backgroundColor);
secondaryColor = getLowContrastColor(backgroundColor);
}
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index 31276ec..6c603c9 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -83,6 +83,38 @@
return result;
}
+ public static Bitmap createCircleWithShadow(int circleColor, int diameter) {
+
+ float shadowRadius = diameter * 1f / 32;
+ float shadowYOffset = diameter * 1f / 16;
+
+ int radius = diameter / 2;
+
+ Canvas canvas = new Canvas();
+ Paint blurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ blurPaint.setMaskFilter(new BlurMaskFilter(shadowRadius, Blur.NORMAL));
+
+ int center = Math.round(radius + shadowRadius + shadowYOffset);
+ int size = center * 2;
+ Bitmap result = Bitmap.createBitmap(size, size, Config.ARGB_8888);
+ canvas.setBitmap(result);
+
+ // Draw ambient shadow, center aligned within size
+ blurPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
+ canvas.drawCircle(center, center, radius, blurPaint);
+
+ // Draw key shadow, bottom aligned within size
+ blurPaint.setAlpha(KEY_SHADOW_ALPHA);
+ canvas.drawCircle(center, center + shadowYOffset, radius, blurPaint);
+
+ // Draw the circle
+ Paint drawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ drawPaint.setColor(circleColor);
+ canvas.drawCircle(center, center, radius, drawPaint);
+
+ return result;
+ }
+
public static ShadowGenerator getInstance(Context context) {
Preconditions.assertNonUiThread();
synchronized (LOCK) {
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
index 7c98362..278669b 100644
--- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -63,7 +63,7 @@
for (String pkg : new HashSet<>(entry.getValue())) {
if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {
- if (pmHelper.isAppOnSdcard(pkg)) {
+ if (pmHelper.isAppOnSdcard(pkg, user)) {
packagesUnavailable.add(pkg);
} else {
packagesRemoved.add(pkg);
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index 742c90a..efd9a3b 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -20,14 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -36,11 +29,11 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.R;
+import com.android.launcher3.anim.PillHeightRevealOutlineProvider;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
import com.android.launcher3.popup.PopupItemView;
import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.anim.PillHeightRevealOutlineProvider;
import java.util.List;
@@ -54,9 +47,6 @@
private static final Rect sTempRect = new Rect();
- private final Paint mBackgroundClipPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG |
- Paint.FILTER_BITMAP_FLAG);
-
private View mDivider;
private NotificationMainView mMainView;
private NotificationFooterLayout mFooter;
@@ -85,35 +75,6 @@
mSwipeHelper.setDisableHardwareLayers(true);
}
- private void initializeBackgroundClipping(boolean force) {
- if (force || mBackgroundClipPaint.getShader() == null) {
- mBackgroundClipPaint.setXfermode(null);
- mBackgroundClipPaint.setShader(null);
- Bitmap backgroundBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
- Bitmap.Config.ALPHA_8);
- Canvas canvas = new Canvas();
- canvas.setBitmap(backgroundBitmap);
- float roundRectRadius = getResources().getDimensionPixelSize(
- R.dimen.bg_round_rect_radius);
- canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
- roundRectRadius, roundRectRadius, mBackgroundClipPaint);
- Shader backgroundClipShader = new BitmapShader(backgroundBitmap,
- Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
- mBackgroundClipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
- mBackgroundClipPaint.setShader(backgroundClipShader);
- }
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- initializeBackgroundClipping(false /* force */);
- int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- super.dispatchDraw(canvas);
- canvas.drawPaint(mBackgroundClipPaint);
- canvas.restoreToCount(saveCount);
- }
-
public Animator animateHeightRemoval(int heightToRemove) {
final int newHeight = getHeight() - heightToRemove;
Animator heightAnimator = new PillHeightRevealOutlineProvider(mPillRect,
@@ -135,11 +96,6 @@
}
@Override
- protected float getBackgroundRadius() {
- return getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius);
- }
-
- @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mMainView.getNotificationInfo() == null) {
// The notification hasn't been populated yet.
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index a627d23..d9f7d76 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -26,6 +26,7 @@
import android.support.v4.util.Pair;
import com.android.launcher3.LauncherModel;
+import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageUserKey;
@@ -55,6 +56,8 @@
private final Handler mWorkerHandler;
private final Handler mUiHandler;
+ private Ranking mTempRanking = new Ranking();
+
private Handler.Callback mWorkerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
@@ -166,7 +169,7 @@
NotificationPostedMsg(StatusBarNotification sbn) {
packageUserKey = PackageUserKey.fromNotification(sbn);
notificationKey = sbn.getKey();
- shouldBeFilteredOut = shouldBeFilteredOut(sbn.getNotification());
+ shouldBeFilteredOut = shouldBeFilteredOut(sbn);
}
}
@@ -190,14 +193,14 @@
* Filter out notifications that don't have an intent
* or are headers for grouped notifications.
*
- * TODO: use the system concept of a badged notification instead
+ * @see #shouldBeFilteredOut(StatusBarNotification)
*/
private List<StatusBarNotification> filterNotifications(
StatusBarNotification[] notifications) {
if (notifications == null) return null;
Set<Integer> removedNotifications = new HashSet<>();
for (int i = 0; i < notifications.length; i++) {
- if (shouldBeFilteredOut(notifications[i].getNotification())) {
+ if (shouldBeFilteredOut(notifications[i])) {
removedNotifications.add(i);
}
}
@@ -211,7 +214,14 @@
return filteredNotifications;
}
- private boolean shouldBeFilteredOut(Notification notification) {
+ private boolean shouldBeFilteredOut(StatusBarNotification sbn) {
+ if (Utilities.isAtLeastO()) {
+ getCurrentRanking().getRanking(sbn.getKey(), mTempRanking);
+ if (!mTempRanking.canShowBadge()) {
+ return true;
+ }
+ }
+ Notification notification = sbn.getNotification();
boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0;
return (notification.contentIntent == null || isGroupHeader);
}
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index b342525..824dbf2 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -22,7 +22,9 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -71,7 +73,9 @@
public void applyColors(IconPalette iconPalette) {
mColorBackground = new ColorDrawable(iconPalette.backgroundColor);
- setBackground(mColorBackground);
+ RippleDrawable rippleDrawable = new RippleDrawable(ColorStateList.valueOf(
+ iconPalette.secondaryColor), mColorBackground, null);
+ setBackground(rippleDrawable);
mIconPalette = iconPalette;
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 7811b96..0b0f88a 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -27,7 +27,6 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
@@ -64,15 +63,15 @@
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.graphics.IconPalette;
import com.android.launcher3.graphics.TriangleShape;
import com.android.launcher3.notification.NotificationItemView;
import com.android.launcher3.shortcuts.DeepShortcutView;
-import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.shortcuts.ShortcutsItemView;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -84,18 +83,17 @@
* A container for shortcuts to deep links within apps.
*/
@TargetApi(Build.VERSION_CODES.N)
-public class PopupContainerWithArrow extends AbstractFloatingView
- implements View.OnLongClickListener, View.OnTouchListener, DragSource,
+public class PopupContainerWithArrow extends AbstractFloatingView implements DragSource,
DragController.DragListener {
- private final Point mIconShift = new Point();
- private final Point mIconLastTouchPos = new Point();
-
protected final Launcher mLauncher;
private final int mStartDragThreshold;
private LauncherAccessibilityDelegate mAccessibilityDelegate;
private final boolean mIsRtl;
+ public ShortcutsItemView mShortcutsItemView;
+ private NotificationItemView mNotificationItemView;
+
protected BubbleTextView mOriginalIcon;
private final Rect mTempRect = new Rect();
private PointF mInterceptTouchDown = new PointF();
@@ -177,6 +175,8 @@
boolean reverseOrder = mIsAboveIcon;
if (reverseOrder) {
removeAllViews();
+ mNotificationItemView = null;
+ mShortcutsItemView = null;
itemsToPopulate = PopupPopulator.reverseItems(itemsToPopulate);
addDummyViews(originalIcon, itemsToPopulate, notificationKeys.length > 1);
@@ -184,24 +184,12 @@
orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
}
- List<DeepShortcutView> shortcutViews = new ArrayList<>();
- NotificationItemView notificationView = null;
- for (int i = 0; i < getChildCount(); i++) {
- View item = getChildAt(i);
- switch (itemsToPopulate[i]) {
- case SHORTCUT:
- if (reverseOrder) {
- shortcutViews.add(0, (DeepShortcutView) item);
- } else {
- shortcutViews.add((DeepShortcutView) item);
- }
- break;
- case NOTIFICATION:
- notificationView = (NotificationItemView) item;
- IconPalette iconPalette = originalIcon.getIconPalette();
- notificationView.applyColors(iconPalette);
- break;
- }
+ List<DeepShortcutView> shortcutViews = mShortcutsItemView == null
+ ? Collections.EMPTY_LIST
+ : mShortcutsItemView.getDeepShortcutViews(reverseOrder);
+ if (mNotificationItemView != null) {
+ IconPalette iconPalette = originalIcon.getIconPalette();
+ mNotificationItemView.applyColors(iconPalette);
}
// Add the arrow.
@@ -221,28 +209,46 @@
final Looper workerLooper = LauncherModel.getWorkerLooper();
new Handler(workerLooper).postAtFrontOfQueue(PopupPopulator.createUpdateRunnable(
mLauncher, (ItemInfo) originalIcon.getTag(), new Handler(Looper.getMainLooper()),
- this, shortcutIds, shortcutViews, notificationKeys, notificationView));
+ this, shortcutIds, shortcutViews, notificationKeys, mNotificationItemView));
}
private void addDummyViews(BubbleTextView originalIcon,
- PopupPopulator.Item[] itemsToPopulate, boolean notificationFooterHasIcons) {
+ PopupPopulator.Item[] itemTypesToPopulate, boolean notificationFooterHasIcons) {
final Resources res = getResources();
- final int spacing = res.getDimensionPixelSize(R.dimen.deep_shortcuts_spacing);
+ final int spacing = res.getDimensionPixelSize(R.dimen.popup_items_spacing);
final LayoutInflater inflater = mLauncher.getLayoutInflater();
- int numItems = itemsToPopulate.length;
+ int numItems = itemTypesToPopulate.length;
for (int i = 0; i < numItems; i++) {
- final PopupItemView item = (PopupItemView) inflater.inflate(
- itemsToPopulate[i].layoutId, this, false);
- if (itemsToPopulate[i] == PopupPopulator.Item.NOTIFICATION) {
+ PopupPopulator.Item itemTypeToPopulate = itemTypesToPopulate[i];
+ final View item = inflater.inflate(itemTypeToPopulate.layoutId, this, false);
+
+ if (itemTypeToPopulate == PopupPopulator.Item.NOTIFICATION) {
+ mNotificationItemView = (NotificationItemView) item;
int footerHeight = notificationFooterHasIcons ?
res.getDimensionPixelSize(R.dimen.notification_footer_height) : 0;
item.findViewById(R.id.footer).getLayoutParams().height = footerHeight;
}
- if (i < numItems - 1) {
- ((LayoutParams) item.getLayoutParams()).bottomMargin = spacing;
- }
+
+ boolean itemIsFollowedByDifferentType = i < numItems - 1
+ && itemTypesToPopulate[i + 1] != itemTypeToPopulate;
+
item.setAccessibilityDelegate(mAccessibilityDelegate);
- addView(item);
+ if (itemTypeToPopulate == PopupPopulator.Item.SHORTCUT) {
+ if (mShortcutsItemView == null) {
+ mShortcutsItemView = (ShortcutsItemView) inflater.inflate(
+ R.layout.shortcuts_item, this, false);
+ addView(mShortcutsItemView);
+ }
+ mShortcutsItemView.addDeepShortcutView((DeepShortcutView) item);
+ if (itemIsFollowedByDifferentType) {
+ ((LayoutParams) mShortcutsItemView.getLayoutParams()).bottomMargin = spacing;
+ }
+ } else {
+ addView(item);
+ if (itemIsFollowedByDifferentType) {
+ ((LayoutParams) item.getLayoutParams()).bottomMargin = spacing;
+ }
+ }
}
// TODO: update this, since not all items are shortcuts
setContentDescription(getContext().getString(R.string.shortcuts_menu_description,
@@ -534,49 +540,8 @@
return true;
}
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- // Touched a shortcut, update where it was touched so we can drag from there on long click.
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY());
- break;
- }
- return false;
- }
-
- public boolean onLongClick(View v) {
- // Return early if this is not initiated from a touch or not the correct view
- if (!v.isInTouchMode() || !(v.getParent() instanceof DeepShortcutView)) return false;
- // Return early if global dragging is not enabled
- if (!mLauncher.isDraggingEnabled()) return false;
- // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
- if (mLauncher.getDragController().isDragging()) return false;
-
- // Long clicked on a shortcut.
- mDeferContainerRemoval = true;
- DeepShortcutView sv = (DeepShortcutView) v.getParent();
- sv.setWillDrawIcon(false);
-
- // Move the icon to align with the center-top of the touch point
- mIconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x;
- mIconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
-
- DragView dv = mLauncher.getWorkspace().beginDragShared(
- sv.getBubbleText(), this, sv.getFinalInfo(),
- new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift), new DragOptions());
- dv.animateShift(-mIconShift.x, -mIconShift.y);
-
- // TODO: support dragging from within folder without having to close it
- AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_FOLDER);
- return false;
- }
-
public void trimNotifications(Map<PackageUserKey, BadgeInfo> updatedBadges) {
- final NotificationItemView notificationView =
- (NotificationItemView) findViewById(R.id.notification_view);
- if (notificationView == null) {
+ if (mNotificationItemView == null) {
return;
}
ItemInfo originalInfo = (ItemInfo) mOriginalIcon.getTag();
@@ -585,11 +550,11 @@
AnimatorSet removeNotification = LauncherAnimUtils.createAnimatorSet();
final int duration = getResources().getInteger(
R.integer.config_removeNotificationViewDuration);
- final int spacing = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_spacing);
+ final int spacing = getResources().getDimensionPixelSize(R.dimen.popup_items_spacing);
removeNotification.play(reduceNotificationViewHeight(
- notificationView.getHeight() + spacing, duration, notificationView));
+ mNotificationItemView.getHeight() + spacing, duration, mNotificationItemView));
final View removeMarginView = mIsAboveIcon ? getItemViewAt(getItemCount() - 2)
- : notificationView;
+ : mNotificationItemView;
if (removeMarginView != null) {
ValueAnimator removeMargin = ValueAnimator.ofFloat(1, 0).setDuration(duration);
removeMargin.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@@ -601,12 +566,12 @@
});
removeNotification.play(removeMargin);
}
- Animator fade = ObjectAnimator.ofFloat(notificationView, ALPHA, 0)
+ Animator fade = ObjectAnimator.ofFloat(mNotificationItemView, ALPHA, 0)
.setDuration(duration);
fade.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- removeView(notificationView);
+ removeView(mNotificationItemView);
if (getItemCount() == 0) {
close(false);
return;
@@ -626,7 +591,7 @@
removeNotification.start();
return;
}
- notificationView.trimNotifications(badgeInfo.getNotificationKeys());
+ mNotificationItemView.trimNotifications(badgeInfo.getNotificationKeys());
}
private ObjectAnimator createArrowScaleAnim(float scale) {
@@ -669,8 +634,7 @@
}
public Animator reduceNotificationViewHeight(int heightToRemove, int duration) {
- return reduceNotificationViewHeight(heightToRemove, duration,
- (NotificationItemView) findViewById(R.id.notification_view));
+ return reduceNotificationViewHeight(heightToRemove, duration, mNotificationItemView);
}
@Override
@@ -702,6 +666,7 @@
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
// Either the original icon or one of the shortcuts was dragged.
// Hide the container, but don't remove it yet because that interferes with touch events.
+ mDeferContainerRemoval = true;
animateClose();
}
@@ -723,7 +688,6 @@
@Override
public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
target.itemType = ItemType.DEEPSHORTCUT;
- target.rank = info.rank;
targetParent.containerType = ContainerType.DEEPSHORTCUTS;
}
@@ -765,38 +729,17 @@
for (int i = firstOpenItemIndex; i < firstOpenItemIndex + numOpenShortcuts; i++) {
final PopupItemView view = getItemViewAt(i);
Animator anim;
- if (view.willDrawIcon()) {
- anim = view.createCloseAnimation(mIsAboveIcon, mIsLeftAligned, duration);
- int animationIndex = mIsAboveIcon ? i - firstOpenItemIndex
- : numOpenShortcuts - i - 1;
- anim.setStartDelay(stagger * animationIndex);
+ anim = view.createCloseAnimation(mIsAboveIcon, mIsLeftAligned, duration);
+ int animationIndex = mIsAboveIcon ? i - firstOpenItemIndex
+ : numOpenShortcuts - i - 1;
+ anim.setStartDelay(stagger * animationIndex);
- Animator fadeAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 0);
- // Don't start fading until the arrow is gone.
- fadeAnim.setStartDelay(stagger * animationIndex + arrowScaleDuration);
- fadeAnim.setDuration(duration - arrowScaleDuration);
- fadeAnim.setInterpolator(fadeInterpolator);
- shortcutAnims.play(fadeAnim);
- } else {
- // The view is being dragged. Animate it such that it collapses with the drag view
- anim = view.collapseToIcon();
- anim.setDuration(DragView.VIEW_ZOOM_DURATION);
-
- // Scale and translate the view to follow the drag view.
- Point iconCenter = view.getIconCenter();
- view.setPivotX(iconCenter.x);
- view.setPivotY(iconCenter.y);
-
- float scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / view.getHeight();
- Animator anim2 = LauncherAnimUtils.ofPropertyValuesHolder(view,
- new PropertyListBuilder()
- .scale(scale)
- .translationX(mIconShift.x)
- .translationY(mIconShift.y)
- .build())
- .setDuration(DragView.VIEW_ZOOM_DURATION);
- shortcutAnims.play(anim2);
- }
+ Animator fadeAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 0);
+ // Don't start fading until the arrow is gone.
+ fadeAnim.setStartDelay(stagger * animationIndex + arrowScaleDuration);
+ fadeAnim.setDuration(duration - arrowScaleDuration);
+ fadeAnim.setInterpolator(fadeInterpolator);
+ shortcutAnims.play(fadeAnim);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/src/com/android/launcher3/popup/PopupItemView.java b/src/com/android/launcher3/popup/PopupItemView.java
index b3d7155..dc4f415 100644
--- a/src/com/android/launcher3/popup/PopupItemView.java
+++ b/src/com/android/launcher3/popup/PopupItemView.java
@@ -21,8 +21,15 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
@@ -31,7 +38,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.PillRevealOutlineProvider;
-import com.android.launcher3.util.PillWidthRevealOutlineProvider;
/**
* An abstract {@link FrameLayout} that supports animating an item's content
@@ -47,6 +53,9 @@
protected View mIconView;
+ private final Paint mBackgroundClipPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG |
+ Paint.FILTER_BITMAP_FLAG);
+
public PopupItemView(Context context) {
this(context, null, 0);
}
@@ -73,12 +82,35 @@
mPillRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
}
- protected ColorStateList getAttachedArrowColor() {
- return getBackgroundTintList();
+ protected void initializeBackgroundClipping(boolean force) {
+ if (force || mBackgroundClipPaint.getShader() == null) {
+ mBackgroundClipPaint.setXfermode(null);
+ mBackgroundClipPaint.setShader(null);
+ Bitmap backgroundBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
+ Bitmap.Config.ALPHA_8);
+ Canvas canvas = new Canvas();
+ canvas.setBitmap(backgroundBitmap);
+ canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
+ getBackgroundRadius(), getBackgroundRadius(), mBackgroundClipPaint);
+ Shader backgroundClipShader = new BitmapShader(backgroundBitmap,
+ Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+ mBackgroundClipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
+ mBackgroundClipPaint.setShader(backgroundClipShader);
+ }
}
- public boolean willDrawIcon() {
- return true;
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ initializeBackgroundClipping(false /* force */);
+ int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
+ Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ super.dispatchDraw(canvas);
+ canvas.drawPaint(mBackgroundClipPaint);
+ canvas.restoreToCount(saveCount);
+ }
+
+ protected ColorStateList getAttachedArrowColor() {
+ return getBackgroundTintList();
}
/**
@@ -126,17 +158,6 @@
}
/**
- * Creates an animator which clips the container to form a circle around the icon.
- */
- public Animator collapseToIcon() {
- int halfHeight = getMeasuredHeight() / 2;
- int iconCenterX = getIconCenter().x;
- return new PillWidthRevealOutlineProvider(mPillRect,
- iconCenterX - halfHeight, iconCenterX + halfHeight)
- .createRevealAnimator(this, true);
- }
-
- /**
* Returns the position of the center of the icon relative to the container.
*/
public Point getIconCenter() {
@@ -148,7 +169,7 @@
}
protected float getBackgroundRadius() {
- return getResources().getDimensionPixelSize(R.dimen.bg_pill_radius);
+ return getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius);
}
/**
@@ -182,8 +203,10 @@
public void setProgress(float progress) {
super.setProgress(progress);
- mZoomView.setScaleX(progress);
- mZoomView.setScaleY(progress);
+ if (mZoomView != null) {
+ mZoomView.setScaleX(progress);
+ mZoomView.setScaleY(progress);
+ }
float height = mOutline.height();
mTranslateView.setTranslationY(mTranslateYMultiplier * (mFullHeight - height));
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index d2814ee..39c2db2 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -196,7 +196,8 @@
@Override
public void run() {
- mShortcutChild.applyShortcutInfo(mShortcutChildInfo, mDetail, mContainer);
+ mShortcutChild.applyShortcutInfo(mShortcutChildInfo, mDetail,
+ mContainer.mShortcutsItemView);
}
}
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 2f07c9a..47a023e 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -17,26 +17,30 @@
package com.android.launcher3.shortcuts;
import android.content.Context;
+import android.graphics.Point;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
+import android.widget.FrameLayout;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.popup.PopupContainerWithArrow;
-import com.android.launcher3.popup.PopupItemView;
+import com.android.launcher3.Utilities;
/**
* A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}.
* This lets us animate the DeepShortcutView (icon and text) separately from the background.
*/
-public class DeepShortcutView extends PopupItemView {
+public class DeepShortcutView extends FrameLayout {
+
+ private static final Point sTempPoint = new Point();
private final Rect mPillRect;
private DeepShortcutTextView mBubbleText;
+ private View mIconView;
private ShortcutInfo mInfo;
private ShortcutInfoCompat mDetail;
@@ -59,6 +63,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mBubbleText = (DeepShortcutTextView) findViewById(R.id.deep_shortcut);
+ mIconView = findViewById(R.id.icon);
}
public DeepShortcutTextView getBubbleText() {
@@ -73,6 +78,17 @@
return mIconView.getVisibility() == View.VISIBLE;
}
+ /**
+ * Returns the position of the center of the icon relative to the container.
+ */
+ public Point getIconCenter() {
+ sTempPoint.y = sTempPoint.x = getMeasuredHeight() / 2;
+ if (Utilities.isRtl(getResources())) {
+ sTempPoint.x = getMeasuredWidth() - sTempPoint.x;
+ }
+ return sTempPoint;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -81,7 +97,7 @@
/** package private **/
public void applyShortcutInfo(ShortcutInfo info, ShortcutInfoCompat detail,
- PopupContainerWithArrow container) {
+ ShortcutsItemView container) {
mInfo = info;
mDetail = detail;
mBubbleText.applyFromShortcutInfo(info);
diff --git a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
new file mode 100644
index 0000000..349c4c9
--- /dev/null
+++ b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
@@ -0,0 +1,180 @@
+/*
+ * 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.shortcuts;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.Point;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertyListBuilder;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
+import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.popup.PopupItemView;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link PopupItemView} that contains all of the {@link DeepShortcutView}s for an app.
+ */
+public class ShortcutsItemView extends PopupItemView implements View.OnLongClickListener,
+ View.OnTouchListener, LogContainerProvider {
+
+ private Launcher mLauncher;
+ private LinearLayout mDeepShortcutsLayout;
+ private final Point mIconShift = new Point();
+ private final Point mIconLastTouchPos = new Point();
+
+ public ShortcutsItemView(Context context) {
+ this(context, null, 0);
+ }
+
+ public ShortcutsItemView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ShortcutsItemView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ mLauncher = Launcher.getLauncher(context);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDeepShortcutsLayout = (LinearLayout) findViewById(R.id.deep_shortcuts);
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent ev) {
+ // Touched a shortcut, update where it was touched so we can drag from there on long click.
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY());
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ // Return early if this is not initiated from a touch or not the correct view
+ if (!v.isInTouchMode() || !(v.getParent() instanceof DeepShortcutView)) return false;
+ // Return early if global dragging is not enabled
+ if (!mLauncher.isDraggingEnabled()) return false;
+ // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
+ if (mLauncher.getDragController().isDragging()) return false;
+
+ // Long clicked on a shortcut.
+ DeepShortcutView sv = (DeepShortcutView) v.getParent();
+ sv.setWillDrawIcon(false);
+
+ // Move the icon to align with the center-top of the touch point
+ mIconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x;
+ mIconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
+
+ DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getBubbleText(),
+ (PopupContainerWithArrow) getParent(), sv.getFinalInfo(),
+ new ShortcutDragPreviewProvider(sv.getIconView(), mIconShift), new DragOptions());
+ dv.animateShift(-mIconShift.x, -mIconShift.y);
+
+ // TODO: support dragging from within folder without having to close it
+ AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_FOLDER);
+ return false;
+ }
+
+ public void addDeepShortcutView(DeepShortcutView deepShortcutView) {
+ if (getNumDeepShortcuts() > 0) {
+ getDeepShortcutAt(getNumDeepShortcuts() - 1).findViewById(R.id.divider)
+ .setVisibility(VISIBLE);
+ }
+ mDeepShortcutsLayout.addView(deepShortcutView);
+ }
+
+ private DeepShortcutView getDeepShortcutAt(int index) {
+ return (DeepShortcutView) mDeepShortcutsLayout.getChildAt(index);
+ }
+
+ private int getNumDeepShortcuts() {
+ return mDeepShortcutsLayout.getChildCount();
+ }
+
+ public List<DeepShortcutView> getDeepShortcutViews(boolean reverseOrder) {
+ int numDeepShortcuts = getNumDeepShortcuts();
+ List<DeepShortcutView> deepShortcutViews = new ArrayList<>(numDeepShortcuts);
+ for (int i = 0; i < numDeepShortcuts; i++) {
+ DeepShortcutView deepShortcut = getDeepShortcutAt(i);
+ if (reverseOrder) {
+ deepShortcutViews.add(0, deepShortcut);
+ } else {
+ deepShortcutViews.add(deepShortcut);
+ }
+ }
+ return deepShortcutViews;
+ }
+
+ @Override
+ public Animator createOpenAnimation(boolean isContainerAboveIcon, boolean pivotLeft) {
+ AnimatorSet openAnimation = LauncherAnimUtils.createAnimatorSet();
+ openAnimation.play(super.createOpenAnimation(isContainerAboveIcon, pivotLeft));
+ for (int i = 0; i < getNumDeepShortcuts(); i++) {
+ View deepShortcutIcon = getDeepShortcutAt(i).getIconView();
+ deepShortcutIcon.setScaleX(0);
+ deepShortcutIcon.setScaleY(0);
+ openAnimation.play(LauncherAnimUtils.ofPropertyValuesHolder(
+ deepShortcutIcon, new PropertyListBuilder().scale(1).build()));
+ }
+ return openAnimation;
+ }
+
+ @Override
+ public Animator createCloseAnimation(boolean isContainerAboveIcon, boolean pivotLeft,
+ long duration) {
+ AnimatorSet closeAnimation = LauncherAnimUtils.createAnimatorSet();
+ closeAnimation.play(super.createCloseAnimation(isContainerAboveIcon, pivotLeft, duration));
+ for (int i = 0; i < getNumDeepShortcuts(); i++) {
+ View deepShortcutIcon = getDeepShortcutAt(i).getIconView();
+ deepShortcutIcon.setScaleX(1);
+ deepShortcutIcon.setScaleY(1);
+ closeAnimation.play(LauncherAnimUtils.ofPropertyValuesHolder(
+ deepShortcutIcon, new PropertyListBuilder().scale(0).build()));
+ }
+ return closeAnimation;
+ }
+
+ @Override
+ public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
+ LauncherLogProto.Target targetParent) {
+ target.itemType = LauncherLogProto.ItemType.DEEPSHORTCUT;
+ target.rank = info.rank;
+ targetParent.containerType = LauncherLogProto.ContainerType.DEEPSHORTCUTS;
+ }
+}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index bfa932b..7629f78 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -40,81 +40,55 @@
*/
public class PackageManagerHelper {
- private static final int FLAG_SUSPENDED = 1<<30;
-
private final Context mContext;
private final PackageManager mPm;
+ private final LauncherAppsCompat mLauncherApps;
public PackageManagerHelper(Context context) {
mContext = context;
mPm = context.getPackageManager();
+ mLauncherApps = LauncherAppsCompat.getInstance(context);
}
/**
* Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
* guarantee that the app is on SD card.
*/
- public boolean isAppOnSdcard(String packageName) {
- return isAppEnabled(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+ public boolean isAppOnSdcard(String packageName, UserHandle user) {
+ ApplicationInfo info = mLauncherApps.getApplicationInfo(
+ packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, user);
+ return info != null && (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
- public boolean isAppEnabled(String packageName) {
- return isAppEnabled(packageName, 0);
- }
-
- public boolean isAppEnabled(String packageName, int flags) {
- try {
- ApplicationInfo info = mPm.getApplicationInfo(packageName, flags);
- return info != null && info.enabled;
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
- }
-
- /**
- * Returns whether a package is suspended for the current user as per
- * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
- */
- public boolean isAppSuspended(String packageName) {
- try {
- ApplicationInfo info = mPm.getApplicationInfo(packageName, 0);
- return info != null && isAppSuspended(info);
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
- }
-
- /**
- * Returns whether the target app is suspended for a given user as per
- * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
- */
+ /**
+ * Returns whether the target app is suspended for a given user as per
+ * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
+ */
public boolean isAppSuspended(String packageName, UserHandle user) {
- ApplicationInfo info =
- LauncherAppsCompat.getInstance(mContext).getApplicationInfo(packageName, user);
+ ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, 0, user);
return info != null && isAppSuspended(info);
}
public boolean isSafeMode() {
- return mPm.isSafeMode();
+ return mContext.getPackageManager().isSafeMode();
}
public Intent getAppLaunchIntent(String pkg, UserHandle user) {
- List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(mContext)
- .getActivityList(pkg, user);
+ List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(pkg, user);
return activities.isEmpty() ? null :
AppInfo.makeLaunchIntent(mContext, activities.get(0), user);
}
- /**
- * Returns whether an application is suspended as per
- * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
- */
+ /**
+ * Returns whether an application is suspended as per
+ * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
+ */
public static boolean isAppSuspended(ApplicationInfo info) {
// The value of FLAG_SUSPENDED was reused by a hidden constant
// ApplicationInfo.FLAG_PRIVILEGED prior to N, so only check for suspended flag on N
// or later.
if (Utilities.ATLEAST_NOUGAT) {
- return (info.flags & FLAG_SUSPENDED) != 0;
+ return (info.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
} else {
return false;
}
diff --git a/src/com/android/launcher3/util/PillWidthRevealOutlineProvider.java b/src/com/android/launcher3/util/PillWidthRevealOutlineProvider.java
deleted file mode 100644
index 89dda3b..0000000
--- a/src/com/android/launcher3/util/PillWidthRevealOutlineProvider.java
+++ /dev/null
@@ -1,41 +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.util;
-
-import android.graphics.Rect;
-
-/**
- * Extension of {@link PillRevealOutlineProvider} which only changes the width of the pill.
- */
-public class PillWidthRevealOutlineProvider extends PillRevealOutlineProvider {
-
- private final int mStartLeft;
- private final int mStartRight;
-
- public PillWidthRevealOutlineProvider(Rect pillRect, int left, int right) {
- super(0, 0, pillRect);
- mOutline.set(pillRect);
- mStartLeft = left;
- mStartRight = right;
- }
-
- @Override
- public void setProgress(float progress) {
- mOutline.left = (int) (progress * mPillRect.left + (1 - progress) * mStartLeft);
- mOutline.right = (int) (progress * mPillRect.right + (1 - progress) * mStartRight);
- }
-}
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index acd589e..d863339 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -18,6 +18,8 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
import android.view.ContextThemeWrapper;
/**
@@ -49,4 +51,21 @@
ta.recycle();
return (int) (255 * alpha + 0.5f);
}
+
+ /**
+ * Scales a color matrix such that, when applied to color R G B A, it produces R' G' B' A' where
+ * R' = r * R
+ * G' = g * G
+ * B' = b * B
+ * A' = a * A
+ *
+ * The matrix will, for instance, turn white into r g b a, and black will remain black.
+ *
+ * @param color The color r g b a
+ * @param target The ColorMatrix to scale
+ */
+ public static void setColorScaleOnMatrix(int color, ColorMatrix target) {
+ target.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
+ Color.blue(color) / 255f, Color.alpha(color) / 255f);
+ }
}