Merge "Add dark widgets theme" into ub-launcher3-dorval-polish
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 2e03576..2bbd76d 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -63,8 +63,8 @@
<com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
android:id="@+id/page_indicator"
android:theme="@style/HomeScreenElementTheme"
- android:layout_width="@dimen/dynamic_grid_page_indicator_height"
- android:layout_height="@dimen/dynamic_grid_page_indicator_height"
+ android:layout_width="@dimen/dynamic_grid_page_indicator_size"
+ android:layout_height="@dimen/dynamic_grid_page_indicator_size"
android:layout_gravity="bottom|left"/>
<include layout="@layout/widgets_view"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index ff605f4..a3c2535 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -53,9 +53,7 @@
android:clipToPadding="false"
android:overScrollMode="never"
android:descendantFocusability="afterDescendants"
- android:focusable="true"
- android:paddingStart="@dimen/dynamic_grid_edge_margin"
- android:paddingEnd="@dimen/dynamic_grid_edge_margin" />
+ android:focusable="true" />
<!-- Fast scroller popup -->
<TextView
diff --git a/res/layout/app_icon.xml b/res/layout/app_icon.xml
index fa6eb89..52df694 100644
--- a/res/layout/app_icon.xml
+++ b/res/layout/app_icon.xml
@@ -14,4 +14,4 @@
limitations under the License.
-->
-<com.android.launcher3.BubbleTextView style="@style/BaseIcon.Workspace" />
+<com.android.launcher3.views.DoubleShadowBubbleTextView style="@style/BaseIcon.Workspace" />
diff --git a/res/layout/folder_icon.xml b/res/layout/folder_icon.xml
index ccc6b01..4093744 100644
--- a/res/layout/folder_icon.xml
+++ b/res/layout/folder_icon.xml
@@ -20,7 +20,7 @@
android:layout_height="match_parent"
android:orientation="vertical"
android:focusable="true" >
- <com.android.launcher3.BubbleTextView
+ <com.android.launcher3.views.DoubleShadowBubbleTextView
style="@style/BaseIcon.Workspace"
android:id="@+id/folder_icon_name"
android:focusable="false"
diff --git a/res/layout/page_indicator.xml b/res/layout/page_indicator.xml
index c5ef6e0..14ff2bd 100644
--- a/res/layout/page_indicator.xml
+++ b/res/layout/page_indicator.xml
@@ -18,7 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@style/HomeScreenElementTheme"
android:layout_width="match_parent"
- android:layout_height="@dimen/dynamic_grid_page_indicator_height">
+ android:layout_height="@dimen/dynamic_grid_page_indicator_size">
<ImageView
android:id="@+id/all_apps_handle"
android:layout_width="48dp"
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index cde6540..4d80aac 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -24,6 +24,7 @@
<com.android.launcher3.folder.FolderPagedView
android:id="@+id/folder_content"
+ android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="8dp"
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index 2063f32..e91f966 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -24,6 +24,7 @@
<com.android.launcher3.folder.FolderPagedView
android:id="@+id/folder_content"
+ android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="8dp"
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index 1062269..4cd03ce 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -42,7 +42,6 @@
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:textAlignment="viewStart"
- launcher:customShadows="false"
launcher:deferShadowGeneration="true"
launcher:iconDisplay="widget_section"
launcher:iconSizeOverride="@dimen/widget_section_icon_size"
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index b40aa14..08073ce 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -24,4 +24,15 @@
<dimen name="fastscroll_popup_padding">10dp</dimen>
<dimen name="fastscroll_popup_text_size">24dp</dimen>
+ <!-- Dynamic grid -->
+ <dimen name="dynamic_grid_overview_bar_item_width">120dp</dimen>
+ <dimen name="dynamic_grid_page_indicator_size">24dp</dimen>
+ <dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
+ <dimen name="dynamic_grid_cell_padding_x">8dp</dimen>
+
+ <!-- Hotseat -->
+ <dimen name="dynamic_grid_hotseat_land_left_nav_bar_right_padding">18dp</dimen>
+ <dimen name="dynamic_grid_hotseat_land_right_nav_bar_right_padding">6dp</dimen>
+ <dimen name="dynamic_grid_hotseat_land_left_nav_bar_gutter_width">24dp</dimen>
+ <dimen name="dynamic_grid_hotseat_land_right_nav_bar_gutter_width">32dp</dimen>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index fc95002..3839eb1 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -44,10 +44,15 @@
<enum name="shortcut_popup" value="4" />
</attr>
<attr name="deferShadowGeneration" format="boolean" />
- <attr name="customShadows" format="boolean" />
<attr name="centerVertically" format="boolean" />
+ </declare-styleable>
+
+ <declare-styleable name="ShadowInfo">
<attr name="ambientShadowColor" format="color" />
+ <attr name="ambientShadowBlur" format="dimension" />
<attr name="keyShadowColor" format="color" />
+ <attr name="keyShadowBlur" format="dimension" />
+ <attr name="keyShadowOffset" format="dimension" />
</declare-styleable>
<!-- PagedView specific attributes. These attributes are used to customize
@@ -112,9 +117,9 @@
<attr name="numHotseatIcons" format="integer" />
<attr name="iconSize" format="float" />
+ <!-- landscapeIconSize defaults to iconSize, if not specified -->
+ <attr name="landscapeIconSize" format="float" />
<attr name="iconTextSize" format="float" />
- <!-- hotseatIconSize defaults to iconSize, if not specified -->
- <attr name="hotseatIconSize" format="float" />
<attr name="defaultLayoutId" format="reference" />
</declare-styleable>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b90de82..71f9edc 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -17,10 +17,9 @@
<resources>
<!-- Dynamic Grid -->
<dimen name="dynamic_grid_edge_margin">16dp</dimen>
- <dimen name="dynamic_grid_page_indicator_height">32dp</dimen>
+ <dimen name="dynamic_grid_page_indicator_size">32dp</dimen>
<dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
- <dimen name="dynamic_grid_page_indicator_gutter_width_left_nav_bar">38dp</dimen>
- <dimen name="dynamic_grid_page_indicator_gutter_width_right_nav_bar">48dp</dimen>
+ <dimen name="dynamic_grid_page_indicator_gutter_width">50dp</dimen>
<dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
<dimen name="dynamic_grid_overview_min_icon_zone_height">80dp</dimen>
<dimen name="dynamic_grid_overview_max_icon_zone_height">120dp</dimen>
@@ -38,7 +37,10 @@
<dimen name="dynamic_grid_hotseat_top_padding">8dp</dimen>
<dimen name="dynamic_grid_hotseat_bottom_padding">2dp</dimen>
<dimen name="dynamic_grid_hotseat_height">80dp</dimen>
- <dimen name="dynamic_grid_hotseat_land_gutter_width">24dp</dimen>
+ <dimen name="dynamic_grid_hotseat_land_left_nav_bar_right_padding">0dp</dimen>
+ <dimen name="dynamic_grid_hotseat_land_right_nav_bar_right_padding">0dp</dimen>
+ <dimen name="dynamic_grid_hotseat_land_left_nav_bar_gutter_width">0dp</dimen>
+ <dimen name="dynamic_grid_hotseat_land_right_nav_bar_gutter_width">0dp</dimen>
<!-- Drop target bar -->
<dimen name="dynamic_grid_drop_target_size">48dp</dimen>
@@ -74,7 +76,7 @@
<dimen name="all_apps_caret_stroke_width">2dp</dimen>
<dimen name="all_apps_caret_shadow_spread">1dp</dimen>
<dimen name="all_apps_caret_size">13dp</dimen>
- <dimen name="all_apps_caret_workspace_offset">4dp</dimen>
+ <dimen name="all_apps_caret_workspace_offset">18dp</dimen>
<!-- Search bar in All Apps -->
<dimen name="all_apps_header_max_elevation">3dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index bc12bb6..d11b002 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -123,16 +123,17 @@
<!-- No shadows in the base theme -->
<item name="android:shadowRadius">0</item>
- <item name="customShadows">false</item>
</style>
<!-- Icon displayed on the worksapce -->
<style name="BaseIcon.Workspace">
- <item name="customShadows">true</item>
<item name="android:shadowRadius">2.0</item>
<item name="android:shadowColor">?attr/workspaceShadowColor</item>
- <item name="keyShadowColor">?attr/workspaceKeyShadowColor</item>
<item name="ambientShadowColor">?attr/workspaceAmbientShadowColor</item>
+ <item name="ambientShadowBlur">2.5dp</item>
+ <item name="keyShadowColor">?attr/workspaceKeyShadowColor</item>
+ <item name="keyShadowBlur">1dp</item>
+ <item name="keyShadowOffset">.5dp</item>
</style>
<!-- Theme for the popup container -->
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index aeda1a2..c582fc5 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -29,7 +29,6 @@
launcher:iconSize="48"
launcher:iconTextSize="13.0"
launcher:numHotseatIcons="3"
- launcher:hotseatIconSize="48"
launcher:defaultLayoutId="@xml/default_workspace_3x3"
/>
@@ -45,7 +44,6 @@
launcher:iconSize="48"
launcher:iconTextSize="13.0"
launcher:numHotseatIcons="3"
- launcher:hotseatIconSize="48"
launcher:defaultLayoutId="@xml/default_workspace_3x3"
/>
@@ -61,7 +59,6 @@
launcher:iconSize="48"
launcher:iconTextSize="13.0"
launcher:numHotseatIcons="5"
- launcher:hotseatIconSize="48"
launcher:defaultLayoutId="@xml/default_workspace_4x4"
/>
@@ -77,7 +74,6 @@
launcher:iconSize="48"
launcher:iconTextSize="13.0"
launcher:numHotseatIcons="5"
- launcher:hotseatIconSize="48"
launcher:defaultLayoutId="@xml/default_workspace_4x4"
/>
@@ -93,7 +89,6 @@
launcher:iconSize="48"
launcher:iconTextSize="13.0"
launcher:numHotseatIcons="5"
- launcher:hotseatIconSize="48"
launcher:defaultLayoutId="@xml/default_workspace_4x4"
/>
@@ -106,10 +101,9 @@
launcher:numFolderRows="4"
launcher:numFolderColumns="4"
launcher:minAllAppsPredictionColumns="4"
- launcher:iconSize="60"
+ launcher:iconSize="54"
launcher:iconTextSize="13.0"
launcher:numHotseatIcons="5"
- launcher:hotseatIconSize="56"
launcher:defaultLayoutId="@xml/default_workspace_4x4"
/>
@@ -122,10 +116,9 @@
launcher:numFolderRows="4"
launcher:numFolderColumns="4"
launcher:minAllAppsPredictionColumns="4"
- launcher:iconSize="60"
+ launcher:iconSize="54"
launcher:iconTextSize="13.0"
launcher:numHotseatIcons="5"
- launcher:hotseatIconSize="56"
launcher:defaultLayoutId="@xml/default_workspace_4x4"
/>
@@ -138,10 +131,9 @@
launcher:numFolderRows="4"
launcher:numFolderColumns="4"
launcher:minAllAppsPredictionColumns="4"
- launcher:iconSize="64"
+ launcher:iconSize="56"
launcher:iconTextSize="14.4"
launcher:numHotseatIcons="5"
- launcher:hotseatIconSize="56"
launcher:defaultLayoutId="@xml/default_workspace_5x5"
/>
@@ -154,10 +146,9 @@
launcher:numFolderRows="4"
launcher:numFolderColumns="5"
launcher:minAllAppsPredictionColumns="4"
- launcher:iconSize="72"
+ launcher:iconSize="64"
launcher:iconTextSize="14.4"
launcher:numHotseatIcons="7"
- launcher:hotseatIconSize="60"
launcher:defaultLayoutId="@xml/default_workspace_5x6"
/>
@@ -173,7 +164,6 @@
launcher:iconSize="76"
launcher:iconTextSize="14.4"
launcher:numHotseatIcons="7"
- launcher:hotseatIconSize="76"
launcher:defaultLayoutId="@xml/default_workspace_5x6"
/>
@@ -189,7 +179,6 @@
launcher:iconSize="100"
launcher:iconTextSize="20.0"
launcher:numHotseatIcons="7"
- launcher:hotseatIconSize="72"
launcher:defaultLayoutId="@xml/default_workspace_5x6"
/>
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index 939fece..c76f118 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -16,23 +16,6 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <SwitchPreference
- android:key="pref_add_icon_to_home"
- android:title="@string/auto_add_shortcuts_label"
- android:summary="@string/auto_add_shortcuts_description"
- android:defaultValue="true"
- android:persistent="true"
- />
-
- <ListPreference
- android:key="pref_override_icon_shape"
- android:title="@string/icon_shape_override_label"
- android:summary="%s"
- android:entries="@array/icon_shape_override_paths_names"
- android:entryValues="@array/icon_shape_override_paths_values"
- android:defaultValue=""
- android:persistent="false" />
-
<Preference
android:key="pref_icon_badging"
android:title="@string/icon_badging_title"
@@ -46,10 +29,27 @@
</Preference>
<SwitchPreference
+ android:key="pref_add_icon_to_home"
+ android:title="@string/auto_add_shortcuts_label"
+ android:summary="@string/auto_add_shortcuts_description"
+ android:defaultValue="true"
+ android:persistent="true"
+ />
+
+ <SwitchPreference
android:key="pref_allowRotation"
android:title="@string/allow_rotation_title"
android:defaultValue="@bool/allow_rotation"
android:persistent="true"
/>
+ <ListPreference
+ android:key="pref_override_icon_shape"
+ android:title="@string/icon_shape_override_label"
+ android:summary="%s"
+ android:entries="@array/icon_shape_override_paths_names"
+ android:entryValues="@array/icon_shape_override_paths_values"
+ android:defaultValue=""
+ android:persistent="false" />
+
</PreferenceScreen>
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index ac7cbaf..c55a586 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -113,20 +113,18 @@
* Calculate the background padding as it can change due to insets/content padding change.
*/
private void updatePaddings() {
- Context context = getContext();
- int paddingLeft;
- int paddingRight;
- int paddingTop;
- int paddingBottom;
-
- DeviceProfile grid = Launcher.getLauncher(context).getDeviceProfile();
+ DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
int[] padding = grid.getContainerPadding();
- paddingLeft = padding[0] + grid.edgeMarginPx;
- paddingRight = padding[1] + grid.edgeMarginPx;
+
+ int paddingLeft = padding[0];
+ int paddingRight = padding[1];
+ int paddingTop = 0;
+ int paddingBottom = 0;
+
if (!grid.isVerticalBarLayout()) {
+ paddingLeft += grid.edgeMarginPx;
+ paddingRight += grid.edgeMarginPx;
paddingTop = paddingBottom = grid.edgeMarginPx;
- } else {
- paddingTop = paddingBottom = 0;
}
updateBackground(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index cb3cbd2..6f2c897 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -27,10 +26,8 @@
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
import android.util.Property;
@@ -48,7 +45,6 @@
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.badge.BadgeRenderer;
import com.android.launcher3.folder.FolderIconPreviewVerifier;
-import com.android.launcher3.folder.FolderPagedView;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.HolographicOutlineHelper;
import com.android.launcher3.graphics.IconPalette;
@@ -64,11 +60,6 @@
*/
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
- // Dimensions in DP
- private static final float AMBIENT_SHADOW_RADIUS = 2.5f;
- private static final float KEY_SHADOW_RADIUS = 1f;
- private static final float KEY_SHADOW_OFFSET = 0.5f;
-
private static final int DISPLAY_WORKSPACE = 0;
private static final int DISPLAY_ALL_APPS = 1;
private static final int DISPLAY_FOLDER = 2;
@@ -78,22 +69,15 @@
private final Launcher mLauncher;
private Drawable mIcon;
private final boolean mCenterVertically;
- private final Drawable mBackground;
- private OnLongClickListener mOnLongClickListener;
+
private final CheckLongPressHelper mLongPressHelper;
private final HolographicOutlineHelper mOutlineHelper;
private final StylusEventHelper mStylusEventHelper;
- private final int mAmbientShadowColor;
- private final int mKeyShadowColor;
-
- private boolean mBackgroundSizeChanged;
+ private final float mSlop;
private Bitmap mPressedBackground;
- private float mSlop;
-
private final boolean mDeferShadowGenerationOnTouch;
- private final boolean mCustomShadowsEnabled;
private final boolean mLayoutHorizontal;
private final int mIconSize;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -122,7 +106,7 @@
}
};
- private static final Property<BubbleTextView, Integer> TEXT_ALPHA_PROPERTY
+ public static final Property<BubbleTextView, Integer> TEXT_ALPHA_PROPERTY
= new Property<BubbleTextView, Integer>(Integer.class, "textAlpha") {
@Override
public Integer get(BubbleTextView bubbleTextView) {
@@ -156,15 +140,13 @@
super(context, attrs, defStyle);
mLauncher = Launcher.getLauncher(context);
DeviceProfile grid = mLauncher.getDeviceProfile();
+ mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
- mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, false);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
mDeferShadowGenerationOnTouch =
a.getBoolean(R.styleable.BubbleTextView_deferShadowGeneration, false);
- mAmbientShadowColor = a.getColor(R.styleable.BubbleTextView_ambientShadowColor, 0x33000000);
- mKeyShadowColor = a.getColor(R.styleable.BubbleTextView_keyShadowColor, 0x66000000);
int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
int defaultIconSize = grid.iconSizePx;
@@ -186,40 +168,18 @@
defaultIconSize);
a.recycle();
- if (mCustomShadowsEnabled) {
- // Draw the background itself as the parent is drawn twice.
- mBackground = getBackground();
- setBackground(null);
-
- // Set shadow layer as the larger shadow to that the textView does not clip the shadow.
- float density = getResources().getDisplayMetrics().density;
- setShadowLayer(density * AMBIENT_SHADOW_RADIUS, 0, 0, mAmbientShadowColor);
- } else {
- mBackground = null;
- }
-
mLongPressHelper = new CheckLongPressHelper(this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
mOutlineHelper = HolographicOutlineHelper.getInstance(getContext());
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
+
}
public void applyFromShortcutInfo(ShortcutInfo info) {
applyFromShortcutInfo(info, false);
}
- @Override
- public void invalidateDrawable(@NonNull Drawable drawable) {
- super.invalidateDrawable(drawable);
-
- if (getParent() != null
- && getParent().getParent() != null
- && getParent().getParent().getParent() instanceof FolderPagedView) {
- ((FolderPagedView) getParent().getParent().getParent()).onIconInvalidated(this);
- }
- }
-
public void applyFromShortcutInfo(ShortcutInfo info, boolean promiseStateChanged) {
applyIconAndLabel(info.iconBitmap, info);
setTag(info);
@@ -275,19 +235,6 @@
}
@Override
- protected boolean setFrame(int left, int top, int right, int bottom) {
- if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
- mBackgroundSizeChanged = true;
- }
- return super.setFrame(left, top, right, bottom);
- }
-
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return who == mBackground || super.verifyDrawable(who);
- }
-
- @Override
public void setTag(Object tag) {
if (tag != null) {
LauncherModel.checkItemInfo((ItemInfo) tag);
@@ -316,21 +263,6 @@
return mIcon;
}
- /** Returns whether the layout is horizontal. */
- public boolean isLayoutHorizontal() {
- return mLayoutHorizontal;
- }
-
- @Override
- public void setOnLongClickListener(OnLongClickListener l) {
- super.setOnLongClickListener(l);
- mOnLongClickListener = l;
- }
-
- public OnLongClickListener getOnLongClickListener() {
- return mOnLongClickListener;
- }
-
@Override
public boolean onTouchEvent(MotionEvent event) {
// Call the superclass onTouchEvent first, because sometimes it changes the state to
@@ -428,54 +360,14 @@
return result;
}
+ @SuppressWarnings("wrongcall")
+ protected void drawWithoutBadge(Canvas canvas) {
+ super.onDraw(canvas);
+ }
+
@Override
- public void draw(Canvas canvas) {
- if (!mCustomShadowsEnabled) {
- super.draw(canvas);
- drawBadgeIfNecessary(canvas);
- return;
- }
-
- final Drawable background = mBackground;
- if (background != null) {
- final int scrollX = getScrollX();
- final int scrollY = getScrollY();
-
- if (mBackgroundSizeChanged) {
- background.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop());
- mBackgroundSizeChanged = false;
- }
-
- if ((scrollX | scrollY) == 0) {
- background.draw(canvas);
- } else {
- canvas.translate(scrollX, scrollY);
- background.draw(canvas);
- canvas.translate(-scrollX, -scrollY);
- }
- }
-
- // If text is transparent, don't draw any shadow
- if ((getCurrentTextColor() >> 24) == 0) {
- getPaint().clearShadowLayer();
- super.draw(canvas);
- drawBadgeIfNecessary(canvas);
- return;
- }
-
- // We enhance the shadow by drawing the shadow twice
- float density = getResources().getDisplayMetrics().density;
- getPaint().setShadowLayer(density * AMBIENT_SHADOW_RADIUS, 0, 0, mAmbientShadowColor);
- super.draw(canvas);
- canvas.save(Canvas.CLIP_SAVE_FLAG);
- canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
- getScrollX() + getWidth(),
- getScrollY() + getHeight(), Region.Op.INTERSECT);
- getPaint().setShadowLayer(
- density * KEY_SHADOW_RADIUS, 0.0f, density * KEY_SHADOW_OFFSET, mKeyShadowColor);
- super.draw(canvas);
- canvas.restore();
-
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
drawBadgeIfNecessary(canvas);
}
@@ -483,7 +375,7 @@
* Draws the icon badge in the top right corner of the icon bounds.
* @param canvas The canvas to draw to.
*/
- private void drawBadgeIfNecessary(Canvas canvas) {
+ protected void drawBadgeIfNecessary(Canvas canvas) {
if (!mForceHideBadge && (hasBadge() || mBadgeScale > 0)) {
getIconBounds(mTempIconBounds);
mTempSpaceForBadgeOffset.set((getWidth() - mIconSize) / 2, getPaddingTop());
@@ -522,14 +414,6 @@
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- if (mBackground != null) mBackground.setCallback(this);
- mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
- }
-
- @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mCenterVertically) {
Paint.FontMetrics fm = getPaint().getFontMetrics();
@@ -543,12 +427,6 @@
}
@Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (mBackground != null) mBackground.setCallback(null);
- }
-
- @Override
public void setTextColor(int color) {
mTextColor = color;
super.setTextColor(color);
@@ -580,7 +458,7 @@
* Creates an animator to fade the text in or out.
* @param fadeIn Whether the text should fade in or fade out.
*/
- public Animator createTextAlphaAnimator(boolean fadeIn) {
+ public ObjectAnimator createTextAlphaAnimator(boolean fadeIn) {
return ObjectAnimator.ofInt(this, TEXT_ALPHA_PROPERTY, fadeIn ? Color.alpha(mTextColor) : 0);
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index d0d33a0..d99a30a 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -53,6 +53,7 @@
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.util.CellAndSpan;
import com.android.launcher3.util.GridOccupancy;
@@ -102,8 +103,8 @@
private OnTouchListener mInterceptTouchListener;
private final StylusEventHelper mStylusEventHelper;
- private final ArrayList<FolderIcon.PreviewBackground> mFolderBackgrounds = new ArrayList<>();
- final FolderIcon.PreviewBackground mFolderLeaveBehind = new FolderIcon.PreviewBackground();
+ private final ArrayList<PreviewBackground> mFolderBackgrounds = new ArrayList<>();
+ final PreviewBackground mFolderLeaveBehind = new PreviewBackground();
private float mBackgroundAlpha;
@@ -153,7 +154,7 @@
@ContainerType private final int mContainerType;
- private final float mChildScale;
+ private final float mChildScale = 1f;
public static final int MODE_SHOW_REORDER_HINT = 0;
public static final int MODE_DRAG_OVER = 1;
@@ -217,8 +218,6 @@
mFolderLeaveBehind.delegateCellX = -1;
mFolderLeaveBehind.delegateCellY = -1;
- mChildScale = mContainerType == HOTSEAT ? grid.inv.hotseatScale : 1f;
-
setAlwaysDrawnWithCacheEnabled(false);
final Resources res = getResources();
@@ -495,7 +494,7 @@
}
for (int i = 0; i < mFolderBackgrounds.size(); i++) {
- FolderIcon.PreviewBackground bg = mFolderBackgrounds.get(i);
+ PreviewBackground bg = mFolderBackgrounds.get(i);
cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation);
canvas.save();
canvas.translate(mTempLocation[0], mTempLocation[1]);
@@ -521,7 +520,7 @@
super.dispatchDraw(canvas);
for (int i = 0; i < mFolderBackgrounds.size(); i++) {
- FolderIcon.PreviewBackground bg = mFolderBackgrounds.get(i);
+ PreviewBackground bg = mFolderBackgrounds.get(i);
if (bg.isClipping) {
cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation);
canvas.save();
@@ -532,10 +531,10 @@
}
}
- public void addFolderBackground(FolderIcon.PreviewBackground bg) {
+ public void addFolderBackground(PreviewBackground bg) {
mFolderBackgrounds.add(bg);
}
- public void removeFolderBackground(FolderIcon.PreviewBackground bg) {
+ public void removeFolderBackground(PreviewBackground bg) {
mFolderBackgrounds.remove(bg);
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 0a346a6..dcfb268 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -19,6 +19,7 @@
import android.appwidget.AppWidgetHostView;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
@@ -32,7 +33,6 @@
import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.badge.BadgeRenderer;
-import com.android.launcher3.config.FeatureFlags;
import java.util.ArrayList;
@@ -80,9 +80,8 @@
public final int workspaceSpringLoadedBottomSpace;
// Page indicator
- private final int pageIndicatorHeightPx;
- private final int pageIndicatorLandGutterLeftNavBarPx;
- private final int pageIndicatorLandGutterRightNavBarPx;
+ private final int pageIndicatorSizePx;
+ private final int pageIndicatorLandGutterPx;
private final int pageIndicatorLandWorkspaceOffsetPx;
// Workspace icons
@@ -93,7 +92,7 @@
public int cellWidthPx;
public int cellHeightPx;
- public int cellPaddingXPx;
+ public int workspaceCellPaddingXPx;
// Folder
public int folderBackgroundOffset;
@@ -110,15 +109,17 @@
public int folderChildDrawablePaddingPx;
// Hotseat
- public int hotseatCellWidthPx;
public int hotseatCellHeightPx;
- public int hotseatIconSizePx;
public int hotseatBarHeightPx;
public int hotseatBarTopPaddingPx;
+ public int hotseatBarLeftNavBarRightPaddingPx;
+ public int hotseatBarRightNavBarRightPaddingPx;
public int hotseatBarBottomPaddingPx;
- public int hotseatLandGutterPx;
+ public int hotseatLandLeftNavBarGutterPx;
+ public int hotseatLandRightNavBarGutterPx;
// All apps
+ public int allAppsCellHeightPx;
public int allAppsNumCols;
public int allAppsNumPredictiveCols;
public int allAppsButtonVisualSize;
@@ -160,19 +161,22 @@
transposeLayoutWithOrientation =
res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
+ context = getContext(context, isVerticalBarLayout()
+ ? Configuration.ORIENTATION_LANDSCAPE
+ : Configuration.ORIENTATION_PORTRAIT);
+ res = context.getResources();
+
+
ComponentName cn = new ComponentName(context.getPackageName(),
this.getClass().getName());
defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
desiredWorkspaceLeftRightMarginPx = edgeMarginPx;
- pageIndicatorHeightPx =
- res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height);
- pageIndicatorLandGutterLeftNavBarPx = res.getDimensionPixelSize(
- R.dimen.dynamic_grid_page_indicator_gutter_width_left_nav_bar);
+ pageIndicatorSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_size);
+ pageIndicatorLandGutterPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_page_indicator_gutter_width);
pageIndicatorLandWorkspaceOffsetPx =
res.getDimensionPixelSize(R.dimen.all_apps_caret_workspace_offset);
- pageIndicatorLandGutterRightNavBarPx = res.getDimensionPixelSize(
- R.dimen.dynamic_grid_page_indicator_gutter_width_right_nav_bar);
defaultPageSpacingPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
topWorkspacePadding =
@@ -182,8 +186,7 @@
overviewModeMaxIconZoneHeightPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_max_icon_zone_height);
overviewModeBarItemWidthPx =
- (int) (res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_item_width)
- * (isLandscape ? 1.5f : 1f));
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_item_width);
overviewModeBarSpacerWidthPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_spacer_width);
overviewModeIconZoneRatio =
@@ -194,15 +197,25 @@
workspaceSpringLoadedBottomSpace =
res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space);
- cellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
+ workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
hotseatBarTopPaddingPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
hotseatBarBottomPaddingPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
- hotseatBarHeightPx = hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx +
- res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height);
- hotseatLandGutterPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_land_gutter_width);
+ hotseatBarLeftNavBarRightPaddingPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_hotseat_land_left_nav_bar_right_padding);
+ hotseatBarRightNavBarRightPaddingPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_hotseat_land_right_nav_bar_right_padding);
+ hotseatBarHeightPx = isVerticalBarLayout()
+ ? res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height)
+ : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height)
+ + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx;
+
+ hotseatLandLeftNavBarGutterPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_hotseat_land_left_nav_bar_gutter_width);
+ hotseatLandRightNavBarGutterPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_hotseat_land_right_nav_bar_gutter_width);
// Determine sizes.
widthPx = width;
@@ -263,7 +276,7 @@
private void computeAllAppsButtonSize(Context context) {
Resources res = context.getResources();
float padding = res.getInteger(R.integer.config_allAppsButtonPaddingPercent) / 100f;
- allAppsButtonVisualSize = (int) (hotseatIconSizePx * (1 - padding)) - context.getResources()
+ allAppsButtonVisualSize = (int) (iconSizePx * (1 - padding)) - context.getResources()
.getDimensionPixelSize(R.dimen.all_apps_button_scale_down);
}
@@ -281,25 +294,33 @@
}
private void updateIconSize(float scale, Resources res, DisplayMetrics dm) {
- iconSizePx = (int) (Utilities.pxFromDp(inv.iconSize, dm) * scale);
+ float invIconSizePx = isVerticalBarLayout() ? inv.landscapeIconSize : inv.iconSize;
+ iconSizePx = (int) (Utilities.pxFromDp(invIconSizePx, dm) * scale);
iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale);
iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale);
- hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale);
+
+ // All apps
+ allAppsIconTextSizePx = iconTextSizePx;
allAppsIconSizePx = iconSizePx;
allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
- allAppsIconTextSizePx = iconTextSizePx;
+ allAppsCellHeightPx = getCellSize().y;
+
+ if (isVerticalBarLayout()) {
+ // Always hide the Workspace text with vertical bar layout.
+ iconTextSizePx = 0;
+ allAppsCellHeightPx += Utilities.calculateTextHeight(allAppsIconTextSizePx);
+ }
cellWidthPx = iconSizePx + iconDrawablePaddingPx;
cellHeightPx = iconSizePx + iconDrawablePaddingPx
+ Utilities.calculateTextHeight(iconTextSizePx);
// Hotseat
- hotseatCellWidthPx = cellWidthPx;
hotseatCellHeightPx = iconSizePx + iconDrawablePaddingPx;
if (!isVerticalBarLayout()) {
int expectedWorkspaceHeight = availableHeightPx - hotseatBarHeightPx
- - pageIndicatorHeightPx - topWorkspacePadding;
+ - pageIndicatorSizePx - topWorkspacePadding;
float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace;
workspaceSpringLoadShrinkFactor = Math.min(
res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f,
@@ -403,22 +424,25 @@
/**
* Returns the workspace padding in the specified orientation.
- * Note that it assumes that while in verticalBarLayout, the nav bar is on the right, as such
- * this value is not reliable.
- * Use {@link #getTotalWorkspacePadding()} instead.
*/
public Rect getWorkspacePadding(Rect recycle) {
Rect padding = recycle == null ? new Rect() : recycle;
if (isVerticalBarLayout()) {
if (mInsets.left > 0) {
- padding.set(mInsets.left + pageIndicatorLandGutterLeftNavBarPx, 0,
- hotseatBarHeightPx + hotseatLandGutterPx - mInsets.left, 2 * edgeMarginPx);
+ padding.set(mInsets.left + pageIndicatorLandGutterPx,
+ 0,
+ hotseatBarHeightPx + hotseatLandLeftNavBarGutterPx
+ + hotseatBarLeftNavBarRightPaddingPx - mInsets.left,
+ edgeMarginPx);
} else {
- padding.set(pageIndicatorLandGutterRightNavBarPx, 0,
- hotseatBarHeightPx + hotseatLandGutterPx, 2 * edgeMarginPx);
+ padding.set(pageIndicatorLandGutterPx,
+ 0,
+ hotseatBarHeightPx + hotseatLandRightNavBarGutterPx
+ + hotseatBarRightNavBarRightPaddingPx,
+ edgeMarginPx);
}
} else {
- int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
+ int paddingBottom = hotseatBarHeightPx + pageIndicatorSizePx;
if (isTablet) {
// Pad the left and right of the workspace to ensure consistent spacing
// between all icons
@@ -460,7 +484,7 @@
return new Rect(mInsets.left,
mInsets.top + dropTargetBarSizePx + edgeMarginPx,
mInsets.left + availableWidthPx,
- mInsets.top + availableHeightPx - hotseatBarHeightPx - pageIndicatorHeightPx -
+ mInsets.top + availableHeightPx - hotseatBarHeightPx - pageIndicatorSizePx -
edgeMarginPx);
}
}
@@ -550,7 +574,12 @@
lp.gravity = Gravity.RIGHT;
lp.width = hotseatBarHeightPx + mInsets.left + mInsets.right;
lp.height = LayoutParams.MATCH_PARENT;
- hotseat.getLayout().setPadding(mInsets.left, mInsets.top, mInsets.right,
+
+ int paddingRight = mInsets.left > 0
+ ? hotseatBarLeftNavBarRightPaddingPx
+ : hotseatBarRightNavBarRightPaddingPx;
+
+ hotseat.getLayout().setPadding(mInsets.left, mInsets.top, mInsets.right + paddingRight,
workspacePadding.bottom);
} else if (isTablet) {
// Pad the hotseat with the workspace padding calculated above
@@ -578,17 +607,15 @@
lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
if (isVerticalBarLayout()) {
if (mInsets.left > 0) {
- lp.leftMargin = mInsets.left + pageIndicatorLandGutterLeftNavBarPx -
- lp.width - pageIndicatorLandWorkspaceOffsetPx;
- } else if (mInsets.right > 0) {
- lp.leftMargin = pageIndicatorLandGutterRightNavBarPx - lp.width -
- pageIndicatorLandWorkspaceOffsetPx;
+ lp.leftMargin = mInsets.left;
+ } else {
+ lp.leftMargin = pageIndicatorLandWorkspaceOffsetPx;
}
lp.bottomMargin = workspacePadding.bottom;
} else {
// Put the page indicators above the hotseat
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- lp.height = pageIndicatorHeightPx;
+ lp.height = pageIndicatorSizePx;
lp.bottomMargin = hotseatBarHeightPx + mInsets.bottom;
}
pageIndicator.setLayoutParams(lp);
@@ -607,6 +634,12 @@
overviewMode.setLayoutParams(lp);
}
+ // Layout the AllAppsRecyclerView
+ View view = launcher.findViewById(R.id.apps_list_view);
+ int paddingLeftRight = hasVerticalBarLayout ? 0 : edgeMarginPx;
+ view.setPadding(paddingLeftRight, view.getPaddingTop(), paddingLeftRight,
+ view.getPaddingBottom());
+
if (notifyListeners) {
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onLauncherLayoutChanged();
@@ -650,9 +683,8 @@
}
// In landscape, we match the width of the workspace
- int padding = (pageIndicatorLandGutterRightNavBarPx +
- hotseatBarHeightPx + hotseatLandGutterPx + mInsets.left) / 2;
- return new int[]{ padding, padding };
+ Rect padding = getWorkspacePadding(null);
+ return new int[] { padding.left - mInsets.left, padding.right + mInsets.left};
}
public boolean shouldIgnoreLongPressToOverview(float touchX) {
@@ -661,4 +693,11 @@
boolean touchedRhsEdge = mInsets.right == 0 && touchX > (widthPx - edgeMarginPx);
return !inMultiWindowMode && (touchedLhsEdge || touchedRhsEdge);
}
+
+ private static Context getContext(Context c, int orientation) {
+ Configuration context = new Configuration(c.getResources().getConfiguration());
+ context.orientation = orientation;
+ return c.createConfigurationContext(context);
+
+ }
}
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 199baaf..1272e0a 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -36,8 +36,6 @@
public class FastBitmapDrawable extends Drawable {
- private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed};
-
private static final float PRESSED_BRIGHTNESS = 100f / 255f;
private static final float DISABLED_DESATURATION = 1f;
private static final float DISABLED_BRIGHTNESS = 0.5f;
@@ -107,17 +105,6 @@
@Override
public void draw(Canvas canvas) {
- drawInternal(canvas);
- }
-
- public void drawWithBrightness(Canvas canvas, float brightness) {
- float oldBrightness = getBrightness();
- setBrightness(brightness);
- drawInternal(canvas);
- setBrightness(oldBrightness);
- }
-
- protected void drawInternal(Canvas canvas) {
canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);
}
@@ -185,6 +172,11 @@
}
@Override
+ public ColorFilter getColorFilter() {
+ return mPaint.getColorFilter();
+ }
+
+ @Override
protected boolean onStateChange(int[] state) {
boolean isPressed = false;
for (int s : state) {
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 09ca5c5..383e6ef 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -170,7 +170,11 @@
}
public Drawable getFullResIcon(LauncherActivityInfo info) {
- return mIconProvider.getIcon(info, mIconDpi);
+ return getFullResIcon(info, true);
+ }
+
+ public Drawable getFullResIcon(LauncherActivityInfo info, boolean flattenDrawable) {
+ return mIconProvider.getIcon(info, mIconDpi, flattenDrawable);
}
protected Bitmap makeDefaultIcon(UserHandle user) {
@@ -749,7 +753,7 @@
}
private static final class IconDB extends SQLiteCacheHelper {
- private final static int DB_VERSION = 15;
+ private final static int DB_VERSION = 16;
private final static int RELEASE_VERSION = DB_VERSION +
(FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java
index a5d3990..6872515 100644
--- a/src/com/android/launcher3/IconProvider.java
+++ b/src/com/android/launcher3/IconProvider.java
@@ -24,8 +24,11 @@
return mSystemState;
}
-
- public Drawable getIcon(LauncherActivityInfo info, int iconDpi) {
+ /**
+ * @param flattenDrawable true if the caller does not care about the specification of the
+ * original icon as long as the flattened version looks the same.
+ */
+ public Drawable getIcon(LauncherActivityInfo info, int iconDpi, boolean flattenDrawable) {
return info.getIcon(iconDpi);
}
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index d224615..d7bebd1 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -76,6 +76,7 @@
public int numFolderRows;
public int numFolderColumns;
public float iconSize;
+ public float landscapeIconSize;
public int iconBitmapSize;
public int fillResIconDpi;
public float iconTextSize;
@@ -84,8 +85,6 @@
* Number of icons inside the hotseat area.
*/
public int numHotseatIcons;
- float hotseatIconSize;
- public float hotseatScale;
int defaultLayoutId;
public DeviceProfile landscapeProfile;
@@ -99,12 +98,12 @@
public InvariantDeviceProfile(InvariantDeviceProfile p) {
this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
p.numFolderRows, p.numFolderColumns, p.minAllAppsPredictionColumns,
- p.iconSize, p.iconTextSize, p.numHotseatIcons, p.hotseatIconSize,
+ p.iconSize, p.landscapeIconSize, p.iconTextSize, p.numHotseatIcons,
p.defaultLayoutId);
}
InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc,
- float is, float its, int hs, float his, int dlId) {
+ float is, float lis, float its, int hs, int dlId) {
name = n;
minWidthDps = w;
minHeightDps = h;
@@ -114,12 +113,10 @@
numFolderColumns = fc;
minAllAppsPredictionColumns = maapc;
iconSize = is;
+ landscapeIconSize = lis;
iconTextSize = its;
numHotseatIcons = hs;
- hotseatIconSize = his;
defaultLayoutId = dlId;
-
- hotseatScale = hotseatIconSize / iconSize;
}
@TargetApi(23)
@@ -152,17 +149,15 @@
minAllAppsPredictionColumns = closestProfile.minAllAppsPredictionColumns;
iconSize = interpolatedDeviceProfileOut.iconSize;
+ landscapeIconSize = interpolatedDeviceProfileOut.landscapeIconSize;
iconBitmapSize = Utilities.pxFromDp(iconSize, dm);
iconTextSize = interpolatedDeviceProfileOut.iconTextSize;
- hotseatIconSize = interpolatedDeviceProfileOut.hotseatIconSize;
fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
// If the partner customization apk contains any grid overrides, apply them
// Supported overrides: numRows, numColumns, iconSize
applyPartnerDeviceProfileOverrides(context, dm);
- hotseatScale = hotseatIconSize / iconSize;
-
Point realSize = new Point();
display.getRealSize(realSize);
// The real size never changes. smallSide and largeSide will remain the
@@ -210,9 +205,9 @@
a.getInt(R.styleable.InvariantDeviceProfile_numFolderColumns, numColumns),
a.getInt(R.styleable.InvariantDeviceProfile_minAllAppsPredictionColumns, numColumns),
iconSize,
+ a.getFloat(R.styleable.InvariantDeviceProfile_landscapeIconSize, iconSize),
a.getFloat(R.styleable.InvariantDeviceProfile_iconTextSize, 0),
a.getInt(R.styleable.InvariantDeviceProfile_numHotseatIcons, numColumns),
- a.getFloat(R.styleable.InvariantDeviceProfile_hotseatIconSize, iconSize),
a.getResourceId(R.styleable.InvariantDeviceProfile_defaultLayoutId, 0)));
a.recycle();
}
@@ -304,14 +299,14 @@
private void add(InvariantDeviceProfile p) {
iconSize += p.iconSize;
+ landscapeIconSize += p.landscapeIconSize;
iconTextSize += p.iconTextSize;
- hotseatIconSize += p.hotseatIconSize;
}
private InvariantDeviceProfile multiply(float w) {
iconSize *= w;
+ landscapeIconSize *= w;
iconTextSize *= w;
- hotseatIconSize *= w;
return this;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 66aab43..26c5c9d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -79,7 +79,6 @@
import android.view.accessibility.AccessibilityManager;
import android.view.animation.OvershootInterpolator;
import android.view.inputmethod.InputMethodManager;
-import android.widget.TextView;
import android.widget.Toast;
import com.android.launcher3.DropTarget.DragObject;
@@ -216,9 +215,9 @@
private static final int ACTIVITY_START_DELAY = 1000;
// How long to wait before the new-shortcut animation automatically pans the workspace
- private static int NEW_APPS_PAGE_MOVE_DELAY = 500;
- private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
- @Thunk static int NEW_APPS_ANIMATION_DELAY = 500;
+ private static final int NEW_APPS_PAGE_MOVE_DELAY = 500;
+ private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
+ @Thunk static final int NEW_APPS_ANIMATION_DELAY = 500;
private final ExtractedColors mExtractedColors = new ExtractedColors();
@@ -232,7 +231,7 @@
private AppWidgetManagerCompat mAppWidgetManager;
private LauncherAppWidgetHost mAppWidgetHost;
- private int[] mTmpAddItemCellCoordinates = new int[2];
+ private final int[] mTmpAddItemCellCoordinates = new int[2];
@Thunk Hotseat mHotseat;
private ViewGroup mOverviewPanel;
@@ -262,15 +261,15 @@
private boolean mPaused = true;
private boolean mOnResumeNeedsLoad;
- private ArrayList<Runnable> mBindOnResumeCallbacks = new ArrayList<Runnable>();
- private ArrayList<Runnable> mOnResumeCallbacks = new ArrayList<Runnable>();
+ private final ArrayList<Runnable> mBindOnResumeCallbacks = new ArrayList<>();
+ private final ArrayList<Runnable> mOnResumeCallbacks = new ArrayList<>();
private ViewOnDrawExecutor mPendingExecutor;
private LauncherModel mModel;
private ModelWriter mModelWriter;
private IconCache mIconCache;
private LauncherAccessibilityDelegate mAccessibilityDelegate;
- private Handler mHandler = new Handler();
+ private final Handler mHandler = new Handler();
private boolean mIsResumeFromActionScreenOff;
private boolean mHasFocus = false;
@@ -284,7 +283,7 @@
// match the sensor state.
private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500;
- private final ArrayList<Integer> mSynchronouslyBoundPages = new ArrayList<Integer>();
+ private final ArrayList<Integer> mSynchronouslyBoundPages = new ArrayList<>();
// We only want to get the SharedPreferences once since it does an FS stat each time we get
// it from the context.
@@ -297,8 +296,8 @@
// the press state and keep this reference to reset the press state when we return to launcher.
private BubbleTextView mWaitingForResume;
- protected static HashMap<String, CustomAppWidget> sCustomAppWidgets =
- new HashMap<String, CustomAppWidget>();
+ protected static final HashMap<String, CustomAppWidget> sCustomAppWidgets =
+ new HashMap<>();
static {
if (TestingUtils.ENABLE_CUSTOM_WIDGET_TEST) {
@@ -311,7 +310,7 @@
// simply unregister this runnable.
private Runnable mExitSpringLoadedModeRunnable;
- @Thunk Runnable mBuildLayersRunnable = new Runnable() {
+ @Thunk final Runnable mBuildLayersRunnable = new Runnable() {
public void run() {
if (mWorkspace != null) {
mWorkspace.buildPageHardwareLayers();
@@ -1063,13 +1062,13 @@
public interface CustomContentCallbacks {
// Custom content is completely shown. {@code fromResume} indicates whether this was caused
// by a onResume or by scrolling otherwise.
- public void onShow(boolean fromResume);
+ void onShow(boolean fromResume);
// Custom content is completely hidden
- public void onHide();
+ void onHide();
// Custom content scroll progress changed. From 0 (not showing) to 1 (fully showing).
- public void onScrollProgressChanged(float progress);
+ void onScrollProgressChanged(float progress);
// Indicates whether the user is allowed to scroll away from the custom content.
boolean isScrollingAllowed();
@@ -1080,28 +1079,28 @@
/**
* Touch interaction leading to overscroll has begun
*/
- public void onScrollInteractionBegin();
+ void onScrollInteractionBegin();
/**
* Touch interaction related to overscroll has ended
*/
- public void onScrollInteractionEnd();
+ void onScrollInteractionEnd();
/**
* Scroll progress, between 0 and 100, when the user scrolls beyond the leftmost
* screen (or in the case of RTL, the rightmost screen).
*/
- public void onScrollChange(float progress, boolean rtl);
+ void onScrollChange(float progress, boolean rtl);
/**
* Called when the launcher is ready to use the overlay
* @param callbacks A set of callbacks provided by Launcher in relation to the overlay
*/
- public void setOverlayCallbacks(LauncherOverlayCallbacks callbacks);
+ void setOverlayCallbacks(LauncherOverlayCallbacks callbacks);
}
public interface LauncherOverlayCallbacks {
- public void onScrollChanged(float progress);
+ void onScrollChanged(float progress);
}
class LauncherOverlayCallbacksImpl implements LauncherOverlayCallbacks {
@@ -1285,7 +1284,7 @@
mDragController.addDragListener(mWorkspace);
// Get the search/delete/uninstall bar
- mDropTargetBar = (DropTargetBar) mDragLayer.findViewById(R.id.drop_target_bar);
+ mDropTargetBar = mDragLayer.findViewById(R.id.drop_target_bar);
// Setup Apps and Widgets
mAppsView = (AllAppsContainerView) findViewById(R.id.apps_view);
@@ -1607,7 +1606,6 @@
}
}
});
- return;
}
});
}
@@ -1744,8 +1742,9 @@
// as slow logic in the callbacks eat into the time the scroller expects for the snapToPage
// animation.
if (isActionMain) {
- boolean callbackAllowsMoveToDefaultScreen = mLauncherCallbacks != null ?
- mLauncherCallbacks.shouldMoveToDefaultScreenOnHomeIntent() : true;
+ boolean callbackAllowsMoveToDefaultScreen =
+ mLauncherCallbacks == null || mLauncherCallbacks
+ .shouldMoveToDefaultScreenOnHomeIntent();
if (shouldMoveToDefaultScreen && !mWorkspace.isTouchActive()
&& callbackAllowsMoveToDefaultScreen) {
@@ -2626,9 +2625,9 @@
if (Utilities.ATLEAST_MARSHMALLOW) {
int left = 0, top = 0;
int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
- if (v instanceof TextView) {
+ if (v instanceof BubbleTextView) {
// Launch from center of icon, not entire view
- Drawable icon = Workspace.getTextViewIcon((TextView) v);
+ Drawable icon = ((BubbleTextView) v).getIcon();
if (icon != null) {
Rect bounds = icon.getBounds();
left = (width - bounds.width()) / 2;
@@ -3196,7 +3195,7 @@
orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != 0) {
orderedScreenIds.remove(Workspace.FIRST_SCREEN_ID);
orderedScreenIds.add(0, Workspace.FIRST_SCREEN_ID);
- mModel.updateWorkspaceScreenOrder(this, orderedScreenIds);
+ LauncherModel.updateWorkspaceScreenOrder(this, orderedScreenIds);
} else if (!FeatureFlags.QSB_ON_FIRST_SCREEN && orderedScreenIds.isEmpty()) {
// If there are no screens, we need to have an empty screen
mWorkspace.addExtraEmptyScreen();
@@ -3283,7 +3282,7 @@
// Get the list of added items and intersect them with the set of items here
final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
- final Collection<Animator> bounceAnims = new ArrayList<Animator>();
+ final Collection<Animator> bounceAnims = new ArrayList<>();
final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
Workspace workspace = mWorkspace;
long newItemsScreenId = -1;
@@ -3667,7 +3666,7 @@
* multiple calls to bind the same list.)
*/
@Thunk ArrayList<AppInfo> mTmpAppsList;
- private Runnable mBindAllApplicationsRunnable = new Runnable() {
+ private final Runnable mBindAllApplicationsRunnable = new Runnable() {
public void run() {
bindAllApplications(mTmpAppsList);
mTmpAppsList = null;
@@ -3871,7 +3870,7 @@
}
}
- private Runnable mBindAllWidgetsRunnable = new Runnable() {
+ private final Runnable mBindAllWidgetsRunnable = new Runnable() {
public void run() {
bindAllWidgets(mAllWidgets);
}
@@ -3942,7 +3941,7 @@
}
private boolean shouldShowDiscoveryBounce() {
- if (mState != mState.WORKSPACE) {
+ if (mState != State.WORKSPACE) {
return false;
}
if (mLauncherCallbacks != null && mLauncherCallbacks.shouldShowDiscoveryBounce()) {
@@ -3951,10 +3950,7 @@
if (!mIsResumeFromActionScreenOff) {
return false;
}
- if (mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false)) {
- return false;
- }
- return true;
+ return !mSharedPrefs.getBoolean(APPS_VIEW_SHOWN, false);
}
protected void moveWorkspaceToDefaultScreen() {
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index 0902b20..b7b75f8 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -26,7 +26,6 @@
import android.preference.PreferenceFragment;
import android.provider.Settings;
import android.provider.Settings.System;
-import android.support.v4.os.BuildCompat;
import com.android.launcher3.graphics.IconShapeOverride;
@@ -85,7 +84,7 @@
}
Preference iconBadgingPref = findPreference(ICON_BADGING_PREFERENCE_KEY);
- if (!BuildCompat.isAtLeastO()) {
+ if (!Utilities.isAtLeastO()) {
getPreferenceScreen().removePreference(
findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY));
getPreferenceScreen().removePreference(iconBadgingPref);
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 3a3e13d..fd708c0 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -120,7 +120,9 @@
// Center the icon/folder
int cHeight = getCellContentHeight();
int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f));
- int cellPaddingX = profile.cellPaddingXPx;
+ int cellPaddingX = mContainerType == CellLayout.WORKSPACE
+ ? profile.workspaceCellPaddingXPx
+ : (int) (profile.edgeMarginPx / 2f);
child.setPadding(cellPaddingX, cellPaddingY, cellPaddingX, 0);
}
} else {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index c2987f8..9100fe2 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -38,7 +38,6 @@
import android.os.DeadObjectException;
import android.os.PowerManager;
import android.os.TransactionTooLargeException;
-import android.support.v4.os.BuildCompat;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -86,7 +85,7 @@
private static final Matrix sInverseMatrix = new Matrix();
public static boolean isAtLeastO() {
- return BuildCompat.isAtLeastO();
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}
public static final boolean ATLEAST_NOUGAT_MR1 =
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 14ba2b7..ad1be7e 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -111,7 +111,7 @@
* sizes (landscape vs portrait).
*/
private static class CacheDb extends SQLiteCacheHelper {
- private static final int DB_VERSION = 7;
+ private static final int DB_VERSION = 8;
private static final String TABLE_NAME = "shortcut_and_widget_previews";
private static final String COLUMN_COMPONENT = "componentName";
@@ -471,7 +471,7 @@
RectF boxRect = drawBoxWithShadow(c, size, size);
Bitmap icon = LauncherIcons.createScaledBitmapWithoutShadow(
- mutateOnMainThread(info.getFullResIcon(mIconCache)), mContext, Build.VERSION_CODES.O);
+ mutateOnMainThread(info.getFullResIcon(mIconCache)), mContext, 0);
Rect src = new Rect(0, 0, icon.getWidth(), icon.getHeight());
boxRect.set(0, 0, iconSize, iconSize);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index b955fe1..767e332 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -51,7 +51,6 @@
import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import android.widget.TextView;
import android.widget.Toast;
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.Launcher.LauncherOverlay;
@@ -71,6 +70,7 @@
import com.android.launcher3.dragndrop.SpringLoadedDragController;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.popup.PopupContainerWithArrow;
@@ -254,7 +254,7 @@
public static final int REORDER_TIMEOUT = 350;
private final Alarm mFolderCreationAlarm = new Alarm();
private final Alarm mReorderAlarm = new Alarm();
- private FolderIcon.PreviewBackground mFolderCreateBg;
+ private PreviewBackground mFolderCreateBg;
private FolderIcon mDragOverFolderIcon = null;
private boolean mCreateUserFolderOnDrop = false;
private boolean mAddToExistingFolderOnDrop = false;
@@ -2082,27 +2082,9 @@
}
}
- /**
- * Returns the drawable for the given text view.
- */
- public static Drawable getTextViewIcon(TextView tv) {
- final Drawable[] drawables = tv.getCompoundDrawables();
- for (int i = 0; i < drawables.length; i++) {
- if (drawables[i] != null) {
- return drawables[i];
- }
- }
- return null;
- }
-
public void startDrag(CellLayout.CellInfo cellInfo, DragOptions options) {
View child = cellInfo.cell;
- // Make sure the drag was started by a long press as opposed to a long click.
- if (!child.isInTouchMode()) {
- return;
- }
-
mDragInfo = cellInfo;
child.setVisibility(INVISIBLE);
@@ -2379,7 +2361,7 @@
// In order to keep everything continuous, we hand off the currently rendered
// folder background to the newly created icon. This preserves animation state.
fi.setFolderBackground(mFolderCreateBg);
- mFolderCreateBg = new FolderIcon.PreviewBackground();
+ mFolderCreateBg = new PreviewBackground();
fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
postAnimationRunnable);
} else {
@@ -3060,7 +3042,7 @@
final int cellX;
final int cellY;
- final FolderIcon.PreviewBackground bg = new FolderIcon.PreviewBackground();
+ final PreviewBackground bg = new PreviewBackground();
public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {
this.layout = layout;
@@ -3869,7 +3851,7 @@
updates.contains(info)) {
ShortcutInfo si = (ShortcutInfo) info;
BubbleTextView shortcut = (BubbleTextView) v;
- Drawable oldIcon = getTextViewIcon(shortcut);
+ Drawable oldIcon = shortcut.getIcon();
boolean oldPromiseState = (oldIcon instanceof PreloadIconDrawable)
&& ((PreloadIconDrawable) oldIcon).hasNotCompleted();
shortcut.applyFromShortcutInfo(si, si.isPromise() != oldPromiseState);
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 051c161..4954e0c 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -299,10 +299,7 @@
@Override
public boolean onLongClick(final View v) {
- // Return early if this is not initiated from a touch
- if (!v.isInTouchMode()) return false;
// When we have exited all apps or are in transition, disregard long clicks
-
if (!mLauncher.isAppsViewVisible() ||
mLauncher.getWorkspace().isSwitchingState()) return false;
// Return if global dragging is not enabled or we are already dragging
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 9c7372f..d6514a8 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
-import android.graphics.Point;
import android.support.animation.DynamicAnimation;
import android.support.animation.SpringAnimation;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -298,8 +297,8 @@
icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout());
icon.setOnFocusChangeListener(mIconFocusListener);
- // Ensure the all apps icon height matches the workspace icons
- icon.getLayoutParams().height = getCellSize().y;
+ // Ensure the all apps icon height matches the workspace icons in portrait mode.
+ icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
return new ViewHolder(icon);
case VIEW_TYPE_DISCOVERY_ITEM:
AppDiscoveryItemView appDiscoveryItemView = (AppDiscoveryItemView) mLayoutInflater
@@ -336,10 +335,6 @@
}
}
- private Point getCellSize() {
- return mLauncher.getDeviceProfile().getCellSize();
- }
-
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index faadce4..4d112c6 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -49,7 +49,7 @@
private static final boolean DBG = false;
private final Interpolator mWorkspaceAccelnterpolator = new AccelerateInterpolator(2f);
- private final Interpolator mHotseatAccelInterpolator = new AccelerateInterpolator(.5f);
+ private final Interpolator mHotseatAccelInterpolator = new AccelerateInterpolator(1.5f);
private final Interpolator mDecelInterpolator = new DecelerateInterpolator(3f);
private final Interpolator mFastOutSlowInInterpolator = new FastOutSlowInInterpolator();
private final VerticalPullDetector.ScrollInterpolator mScrollInterpolator
diff --git a/src/com/android/launcher3/allapps/VerticalPullDetector.java b/src/com/android/launcher3/allapps/VerticalPullDetector.java
index 7800c01..13c4f63 100644
--- a/src/com/android/launcher3/allapps/VerticalPullDetector.java
+++ b/src/com/android/launcher3/allapps/VerticalPullDetector.java
@@ -17,7 +17,7 @@
private static final boolean DBG = false;
private static final String TAG = "VerticalPullDetector";
- private float mTouchSlop;
+ private final float mTouchSlop;
private int mScrollConditions;
public static final int DIRECTION_UP = 1 << 0;
@@ -47,8 +47,6 @@
SETTLING // onDragEnd
}
- ;
-
//------------------- ScrollState transition diagram -----------------------------------
//
// IDLE -> (mDisplacement > mTouchSlop) -> DRAGGING
@@ -110,7 +108,7 @@
private boolean mIgnoreSlopWhenSettling;
/* Client of this gesture detector can register a callback. */
- Listener mListener;
+ private Listener mListener;
public void setListener(Listener l) {
mListener = l;
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 8e5452e..3f06ec9 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -23,13 +23,11 @@
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
-import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.FrameLayout;
-
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Launcher;
@@ -43,7 +41,6 @@
import com.android.launcher3.discovery.AppDiscoveryUpdateState;
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.util.ComponentKey;
-
import java.util.ArrayList;
/**
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index 647c315..cc3e5a7 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -29,23 +29,22 @@
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-
+import android.util.ArrayMap;
import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.PackageUserKey;
-
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
public class LauncherAppsCompatVL extends LauncherAppsCompat {
protected final LauncherApps mLauncherApps;
protected final Context mContext;
- private Map<OnAppsChangedCallbackCompat, WrappedCallback> mCallbacks = new HashMap<>();
+ private final ArrayMap<OnAppsChangedCallbackCompat, WrappedCallback> mCallbacks =
+ new ArrayMap<>();
LauncherAppsCompatVL(Context context) {
mContext = context;
@@ -131,43 +130,52 @@
}
private static class WrappedCallback extends LauncherApps.Callback {
- private LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback;
+ private final LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback;
public WrappedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
mCallback = callback;
}
+ @Override
public void onPackageRemoved(String packageName, UserHandle user) {
mCallback.onPackageRemoved(packageName, user);
}
+ @Override
public void onPackageAdded(String packageName, UserHandle user) {
mCallback.onPackageAdded(packageName, user);
}
+ @Override
public void onPackageChanged(String packageName, UserHandle user) {
mCallback.onPackageChanged(packageName, user);
}
+ @Override
public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
mCallback.onPackagesAvailable(packageNames, user, replacing);
}
+ @Override
public void onPackagesUnavailable(String[] packageNames, UserHandle user,
boolean replacing) {
mCallback.onPackagesUnavailable(packageNames, user, replacing);
}
+ @Override
public void onPackagesSuspended(String[] packageNames, UserHandle user) {
mCallback.onPackagesSuspended(packageNames, user);
}
+ @Override
public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
mCallback.onPackagesUnsuspended(packageNames, user);
}
- public void onShortcutsChanged(String packageName, List<ShortcutInfo> shortcuts,
- UserHandle user) {
+ @Override
+ public void onShortcutsChanged(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts,
+ @NonNull UserHandle user) {
List<ShortcutInfoCompat> shortcutInfoCompats = new ArrayList<>(shortcuts.size());
for (ShortcutInfo shortcutInfo : shortcuts) {
shortcutInfoCompats.add(new ShortcutInfoCompat(shortcutInfo));
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 29789c8..01893bd 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -84,6 +84,8 @@
private int mPendingBindWidgetId;
private Bundle mWidgetOptions;
+ private boolean mFinishOnPause = false;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -163,6 +165,7 @@
startActivity(homeIntent,
ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out).toBundle());
+ mFinishOnPause = true;
// Start a system drag and drop. We use a transparent bitmap as preview for system drag
// as the preview is handled internally by launcher.
@@ -182,6 +185,14 @@
return false;
}
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (mFinishOnPause) {
+ finish();
+ }
+ }
+
private void setupShortcut() {
PinShortcutRequestActivityInfo shortcutInfo =
new PinShortcutRequestActivityInfo(mRequest, this);
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 50ad0ff..b852714 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -210,13 +210,13 @@
}
private void callOnDragStart() {
- for (DragListener listener : new ArrayList<>(mListeners)) {
- listener.onDragStart(mDragObject, mOptions);
- }
if (mOptions.preDragCondition != null) {
mOptions.preDragCondition.onPreDragEnd(mDragObject, true /* dragStarted*/);
}
mIsInPreDrag = false;
+ for (DragListener listener : new ArrayList<>(mListeners)) {
+ listener.onDragStart(mDragObject, mOptions);
+ }
}
/**
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 9626cc6..022b3b8 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -29,6 +29,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
@@ -39,6 +40,7 @@
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
@@ -50,6 +52,7 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
@@ -59,12 +62,19 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.ShortcutConfigActivityInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.IconNormalizer;
+import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.Arrays;
+import java.util.List;
public class DragView extends FrameLayout {
public static final int COLOR_CHANGE_DURATION = 120;
@@ -195,7 +205,8 @@
if (!(FeatureFlags.LAUNCHER3_SPRING_ICONS && Utilities.isAtLeastO())) {
return;
}
- if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+ if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
+ info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
return;
}
// Load the adaptive icon on a background thread and add the view in ui thread.
@@ -204,10 +215,9 @@
@Override
public void run() {
LauncherAppState appState = LauncherAppState.getInstance(mLauncher);
- LauncherActivityInfo activityInfo = LauncherAppsCompat.getInstance(mLauncher)
- .resolveActivity(info.getIntent(), info.user);
- Drawable dr = (activityInfo != null) ? appState.getIconCache()
- .getFullResIcon(activityInfo) : null;
+ Object[] outObj = new Object[1];
+ Drawable dr = getFullDrawable(info, appState, outObj);
+
if (dr instanceof AdaptiveIconDrawable) {
int w = mBitmap.getWidth();
int h = mBitmap.getHeight();
@@ -224,10 +234,7 @@
mSpringX = setupSpringAnimation(-w/4, w/4, DynamicAnimation.TRANSLATION_X);
mSpringY = setupSpringAnimation(-h/4, h/4, DynamicAnimation.TRANSLATION_Y);
- mBadge = mLauncher.getPackageManager()
- .getUserBadgedIcon(new FixedSizeEmptyDrawable(
- appState.getInvariantDeviceProfile().iconBitmapSize),
- activityInfo.getUser());
+ mBadge = getBadge(info, appState, outObj[0]);
int blurMargin = (int) blurSizeOutline / 2;
mBadge.setBounds(blurMargin, blurMargin, w - blurMargin, h - blurMargin);
@@ -239,12 +246,84 @@
addView(mBgImageView);
addView(mFgImageView);
setWillNotDraw(true);
+
+ if (info.isDisabled()) {
+ FastBitmapDrawable d = new FastBitmapDrawable(null);
+ d.setIsDisabled(true);
+ ColorFilter cf = d.getColorFilter();
+ mBgImageView.setColorFilter(cf);
+ mFgImageView.setColorFilter(cf);
+ mBadge.setColorFilter(cf);
+ }
}
});
}
}});
}
+ /**
+ * Returns the full drawable for {@param info}.
+ * @param outObj this is set to the internal data associated with {@param info},
+ * eg {@link LauncherActivityInfo} or {@link ShortcutInfoCompat}.
+ */
+ private Drawable getFullDrawable(ItemInfo info, LauncherAppState appState, Object[] outObj) {
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+ LauncherActivityInfo activityInfo = LauncherAppsCompat.getInstance(mLauncher)
+ .resolveActivity(info.getIntent(), info.user);
+ outObj[0] = activityInfo;
+ return (activityInfo != null) ? appState.getIconCache()
+ .getFullResIcon(activityInfo, false) : null;
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ if (info instanceof PendingAddShortcutInfo) {
+ ShortcutConfigActivityInfo activityInfo =
+ ((PendingAddShortcutInfo) info).activityInfo;
+ outObj[0] = activityInfo;
+ return activityInfo.getFullResIcon(appState.getIconCache());
+ }
+ ShortcutKey key = ShortcutKey.fromItemInfo(info);
+ DeepShortcutManager sm = DeepShortcutManager.getInstance(mLauncher);
+ List<ShortcutInfoCompat> si = sm.queryForFullDetails(
+ key.componentName.getPackageName(), Arrays.asList(key.getId()), key.user);
+ if (si.isEmpty()) {
+ return null;
+ } else {
+ outObj[0] = si.get(0);
+ return sm.getShortcutIconDrawable(si.get(0),
+ appState.getInvariantDeviceProfile().fillResIconDpi);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * For apps icons and shortcut icons that have badges, this method creates a drawable that can
+ * later on be rendered on top of the layers for the badges. For app icons, work profile badges
+ * can only be applied. For deep shortcuts, when dragged from the pop up container, there's no
+ * badge. When dragged from workspace or folder, it may contain app AND/OR work profile badge
+ **/
+
+ @TargetApi(Build.VERSION_CODES.O)
+ private Drawable getBadge(ItemInfo info, LauncherAppState appState, Object obj) {
+ int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize;
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ if (info.id == ItemInfo.NO_ID || !(obj instanceof ShortcutInfoCompat)) {
+ // The item is not yet added on home screen.
+ return new FixedSizeEmptyDrawable(iconSize);
+ }
+ ShortcutInfoCompat si = (ShortcutInfoCompat) obj;
+ Bitmap badge = LauncherIcons.getShortcutInfoBadge(si, appState.getIconCache());
+
+ float badgeSize = mLauncher.getResources().getDimension(R.dimen.profile_badge_size);
+ float insetFraction = (iconSize - badgeSize) / iconSize;
+ return new InsetDrawable(new FastBitmapDrawable(badge),
+ insetFraction, insetFraction, 0, 0);
+ } else {
+ return mLauncher.getPackageManager()
+ .getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user);
+ }
+ }
+
private ImageView setupImageView(Drawable drawable, float normalizationScale) {
FrameLayout.LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
ImageView imageViewOut = new ImageView(getContext());
diff --git a/src/com/android/launcher3/dynamicui/ExtractionUtils.java b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
index 92cb5dc..cc0e0be 100644
--- a/src/com/android/launcher3/dynamicui/ExtractionUtils.java
+++ b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
@@ -29,6 +29,7 @@
import android.support.v7.graphics.Palette;
import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
import java.util.List;
@@ -47,6 +48,9 @@
* Launcher will be notified in Launcher#onSettingsChanged(String, String).
*/
public static void startColorExtractionServiceIfNecessary(final Context context) {
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ return;
+ }
// Run on a background thread, since the service is asynchronous anyway.
Utilities.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
@@ -60,6 +64,9 @@
/** Starts the {@link ColorExtractionService} without checking the wallpaper id */
public static void startColorExtractionService(Context context) {
+ if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
+ return;
+ }
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(
Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(new JobInfo.Builder(Utilities.COLOR_EXTRACTION_JOB_ID,
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index 0df787a..ff357c0 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -20,7 +20,7 @@
private float mBaselineIconScale;
@Override
- public void init(int availableSpace, int intrinsicIconSize, boolean rtl) {
+ public void init(int availableSpace, float intrinsicIconSize, boolean rtl) {
mAvailableSpace = availableSpace;
mRadius = ITEM_RADIUS_SCALE_FACTOR * availableSpace / 2f;
mIconSize = intrinsicIconSize;
@@ -29,8 +29,8 @@
}
@Override
- public FolderIcon.PreviewItemDrawingParams computePreviewItemDrawingParams(int index,
- int curNumItems, FolderIcon.PreviewItemDrawingParams params) {
+ public PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
+ PreviewItemDrawingParams params) {
float totalScale = scaleForItem(index, curNumItems);
float transX;
@@ -47,7 +47,7 @@
}
if (params == null) {
- params = new FolderIcon.PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
+ params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
} else {
params.update(transX, transY, totalScale);
params.overlayAlpha = overlayAlpha;
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 2838351..aad8123 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -283,9 +283,6 @@
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
ShortcutInfo item = (ShortcutInfo) tag;
- if (!v.isInTouchMode()) {
- return false;
- }
mEmptyCellRank = item.rank;
mCurrentDragView = v;
@@ -335,6 +332,7 @@
if (mIsExternalDrag && mDragInProgress) {
completeDragExit();
}
+ mDragInProgress = false;
mDragController.removeDragListener(this);
}
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 74e8d3b..3648c60 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -37,6 +37,7 @@
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.PropertyResetListener;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.util.Themes;
@@ -57,7 +58,7 @@
private GradientDrawable mFolderBackground;
private FolderIcon mFolderIcon;
- private FolderIcon.PreviewBackground mPreviewBackground;
+ private PreviewBackground mPreviewBackground;
private Context mContext;
private Launcher mLauncher;
@@ -70,8 +71,7 @@
private final TimeInterpolator mFolderInterpolator;
private final TimeInterpolator mLargeFolderPreviewItemInterpolator;
- private final FolderIcon.PreviewItemDrawingParams mTmpParams =
- new FolderIcon.PreviewItemDrawingParams(0, 0, 0, 0);
+ private final PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
private static final Property<View, Float> SCALE_PROPERTY =
new Property<View, Float>(Float.class, "scale") {
@@ -87,23 +87,6 @@
}
};
- private static final Property<List<BubbleTextView>, Integer> ITEMS_TEXT_COLOR_PROPERTY =
- new Property<List<BubbleTextView>, Integer>(Integer.class, "textColor") {
- @Override
- public Integer get(List<BubbleTextView> items) {
- return items.get(0).getCurrentTextColor();
- }
-
- @Override
- public void set(List<BubbleTextView> items, Integer color) {
- int size = items.size();
-
- for (int i = 0; i < size; ++i) {
- items.get(i).setTextColor(color);
- }
- }
- };
-
public FolderAnimationManager(Folder folder, boolean isOpening) {
mFolder = folder;
mContent = folder.mContent;
@@ -183,12 +166,6 @@
ColorUtils.setAlphaComponent(finalColor, mPreviewBackground.getBackgroundAlpha());
mFolderBackground.setColor(mIsOpening ? initialColor : finalColor);
- // Initialize the Folder items' text.
- final List<BubbleTextView> items = mFolder.getItemsOnCurrentPage();
- final int finalTextColor = Themes.getAttrColor(mContext, android.R.attr.textColorSecondary);
- ITEMS_TEXT_COLOR_PROPERTY.set(items, mIsOpening ? Color.TRANSPARENT
- : finalTextColor);
-
// Set up the reveal animation that clips the Folder.
int totalOffsetX = paddingOffsetX + previewItemOffsetX;
Rect startRect = new Rect(
@@ -203,30 +180,41 @@
// Create the animators.
AnimatorSet a = LauncherAnimUtils.createAnimatorSet();
+ // Initialize the Folder items' text.
+ PropertyResetListener colorResetListener = new PropertyResetListener(
+ BubbleTextView.TEXT_ALPHA_PROPERTY,
+ Color.alpha(Themes.getAttrColor(mContext, android.R.attr.textColorSecondary)));
+ for (BubbleTextView icon : mFolder.getItemsOnCurrentPage()) {
+ if (mIsOpening) {
+ icon.setTextVisibility(false);
+ }
+ ObjectAnimator anim = icon.createTextAlphaAnimator(mIsOpening);
+ anim.addListener(colorResetListener);
+ play(a, anim);
+ }
+
play(a, getAnimator(mFolder, View.TRANSLATION_X, xDistance, 0f));
play(a, getAnimator(mFolder, View.TRANSLATION_Y, yDistance, 0f));
play(a, getAnimator(mFolder, SCALE_PROPERTY, initialScale, finalScale));
- play(a, getAnimator(items, ITEMS_TEXT_COLOR_PROPERTY, Color.TRANSPARENT, finalTextColor));
play(a, getAnimator(mFolderBackground, "color", initialColor, finalColor));
play(a, mFolderIcon.mFolderName.createTextAlphaAnimator(!mIsOpening));
play(a, new RoundedRectRevealOutlineProvider(initialRadius, finalRadius, startRect,
endRect).createRevealAnimator(mFolder, !mIsOpening));
+ // Animate the elevation midway so that the shadow is not noticeable in the background.
+ int midDuration = mDuration / 2;
+ Animator z = getAnimator(mFolder, View.TRANSLATION_Z, -mFolder.getElevation(), 0);
+ play(a, z, midDuration, midDuration);
+
a.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- ITEMS_TEXT_COLOR_PROPERTY.set(items, finalTextColor);
mFolder.setTranslationX(0.0f);
mFolder.setTranslationY(0.0f);
+ mFolder.setTranslationZ(0.0f);
mFolder.setScaleX(1f);
mFolder.setScaleY(1f);
-
- if (mIsOpening) {
- getAnimator(mFolder, View.TRANSLATION_Z, -mFolder.getElevation(), 0)
- .setDuration(150)
- .start();
- }
}
});
@@ -335,7 +323,12 @@
}
private void play(AnimatorSet as, Animator a) {
- a.setDuration(mDuration);
+ play(as, a, a.getStartDelay(), mDuration);
+ }
+
+ private void play(AnimatorSet as, Animator a, long startDelay, int duration) {
+ a.setStartDelay(startDelay);
+ a.setDuration(duration);
as.play(a);
}
@@ -355,12 +348,6 @@
: ObjectAnimator.ofFloat(view, property, v2, v1);
}
- private Animator getAnimator(List<BubbleTextView> items, Property property, int v1, int v2) {
- return mIsOpening
- ? ObjectAnimator.ofArgb(items, property, v1, v2)
- : ObjectAnimator.ofArgb(items, property, v2, v1);
- }
-
private Animator getAnimator(GradientDrawable drawable, String property, int v1, int v2) {
return mIsOpening
? ObjectAnimator.ofArgb(drawable, property, v1, v2)
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index b6f05f3..1cc285e 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -19,24 +19,14 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Region;
-import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
-import android.support.v4.graphics.ColorUtils;
+import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Property;
import android.view.LayoutInflater;
@@ -56,7 +46,6 @@
import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.FolderInfo.FolderListener;
import com.android.launcher3.ItemInfo;
@@ -75,8 +64,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
-import com.android.launcher3.graphics.PreloadIconDrawable;
-import com.android.launcher3.util.Themes;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -100,8 +87,6 @@
private CheckLongPressHelper mLongPressHelper;
private StylusEventHelper mStylusEventHelper;
- // The number of icons to display in the
- private static final int CONSUMPTION_ANIMATION_DURATION = 100;
private static final int DROP_IN_ANIMATION_DURATION = 400;
private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
@@ -116,7 +101,7 @@
// These variables are all associated with the drawing of the preview; they are stored
// as member variables for shared usage and to avoid computation on each frame
- private int mIntrinsicIconSize = -1;
+ private float mIntrinsicIconSize = -1;
private int mTotalWidth = -1;
private int mPrevTopPadding = -1;
@@ -132,7 +117,7 @@
FolderIconPreviewVerifier mPreviewVerifier;
private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
- private ArrayList<PreviewItemDrawingParams> mDrawingParams = new ArrayList<PreviewItemDrawingParams>();
+ private ArrayList<PreviewItemDrawingParams> mDrawingParams = new ArrayList<>();
private Drawable mReferenceDrawable = null;
private Alarm mOpenAlarm = new Alarm();
@@ -240,8 +225,7 @@
}
public boolean acceptDrop(ItemInfo dragInfo) {
- final ItemInfo item = dragInfo;
- return !mFolder.isDestroyed() && willAcceptItem(item);
+ return !mFolder.isDestroyed() && willAcceptItem(dragInfo);
}
public void addItem(ShortcutInfo item) {
@@ -436,39 +420,6 @@
return mBadgeInfo != null && mBadgeInfo.hasBadge();
}
- static class PreviewItemDrawingParams {
- PreviewItemDrawingParams(float transX, float transY, float scale, float overlayAlpha) {
- this.transX = transX;
- this.transY = transY;
- this.scale = scale;
- this.overlayAlpha = overlayAlpha;
- }
-
- public void update(float transX, float transY, float scale) {
- // We ensure the update will not interfere with an animation on the layout params
- // If the final values differ, we cancel the animation.
- if (anim != null) {
- if (anim.finalTransX == transX || anim.finalTransY == transY
- || anim.finalScale == scale) {
- return;
- }
- anim.cancel();
- }
-
- this.transX = transX;
- this.transY = transY;
- this.scale = scale;
- }
-
- float transX;
- float transY;
- float scale;
- public float overlayAlpha;
- boolean hidden;
- FolderPreviewItemAnim anim;
- Drawable drawable;
- }
-
private float getLocalCenterForIndex(int index, int curNumItems, int[] center) {
mTmpParams = computePreviewItemDrawingParams(
Math.min(mPreviewLayoutRule.maxNumItems(), index), curNumItems, mTmpParams);
@@ -478,12 +429,12 @@
float offsetX = mTmpParams.transX + (mTmpParams.scale * mIntrinsicIconSize) / 2;
float offsetY = mTmpParams.transY + (mTmpParams.scale * mIntrinsicIconSize) / 2;
- center[0] = (int) Math.round(offsetX);
- center[1] = (int) Math.round(offsetY);
+ center[0] = Math.round(offsetX);
+ center[1] = Math.round(offsetY);
return mTmpParams.scale;
}
- private PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
+ PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
PreviewItemDrawingParams params) {
// We use an index of -1 to represent an icon on the workspace for the destroy and
// create animations
@@ -510,410 +461,16 @@
Drawable d = params.drawable;
if (d != null) {
- mTempBounds.set(d.getBounds());
- d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
- boolean isPreloadIcon = d instanceof PreloadIconDrawable;
- if (!isPreloadIcon && d instanceof FastBitmapDrawable) {
- FastBitmapDrawable fd = (FastBitmapDrawable) d;
- fd.drawWithBrightness(canvas, params.overlayAlpha);
- } else {
- d.setColorFilter(Color.argb((int) (params.overlayAlpha * 255), 255, 255, 255),
- PorterDuff.Mode.SRC_ATOP);
- d.draw(canvas);
- d.clearColorFilter();
- }
- d.setBounds(mTempBounds);
+ Rect bounds = d.getBounds();
+ canvas.save();
+ canvas.translate(-bounds.left, -bounds.top);
+ canvas.scale(mIntrinsicIconSize / bounds.width(), mIntrinsicIconSize / bounds.height());
+ d.draw(canvas);
+ canvas.restore();
}
canvas.restore();
}
- /**
- * This object represents a FolderIcon preview background. It stores drawing / measurement
- * information, handles drawing, and animation (accept state <--> rest state).
- */
- public static class PreviewBackground {
-
- private final PorterDuffXfermode mClipPorterDuffXfermode
- = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
- // Create a RadialGradient such that it draws a black circle and then extends with
- // transparent. To achieve this, we keep the gradient to black for the range [0, 1) and
- // just at the edge quickly change it to transparent.
- private final RadialGradient mClipShader = new RadialGradient(0, 0, 1,
- new int[] {Color.BLACK, Color.BLACK, Color.TRANSPARENT },
- new float[] {0, 0.999f, 1},
- Shader.TileMode.CLAMP);
-
- private final PorterDuffXfermode mShadowPorterDuffXfermode
- = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
- private RadialGradient mShadowShader = null;
-
- private final Matrix mShaderMatrix = new Matrix();
- private final Path mPath = new Path();
-
- private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
- private float mScale = 1f;
- private float mColorMultiplier = 1f;
- private int mBgColor;
- private float mStrokeWidth;
- private int mStrokeAlpha = MAX_BG_OPACITY;
- private int mShadowAlpha = 255;
- private View mInvalidateDelegate;
-
- public int previewSize;
- private int basePreviewOffsetX;
- private int basePreviewOffsetY;
-
- private CellLayout mDrawingDelegate;
- public int delegateCellX;
- public int delegateCellY;
-
- // When the PreviewBackground is drawn under an icon (for creating a folder) the border
- // should not occlude the icon
- public boolean isClipping = true;
-
- // Drawing / animation configurations
- private static final float ACCEPT_SCALE_FACTOR = 1.25f;
- private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
-
- // Expressed on a scale from 0 to 255.
- private static final int BG_OPACITY = 160;
- private static final int MAX_BG_OPACITY = 225;
- private static final int SHADOW_OPACITY = 40;
-
- ValueAnimator mScaleAnimator;
- ObjectAnimator mStrokeAlphaAnimator;
- ObjectAnimator mShadowAnimator;
-
- private static final Property<PreviewBackground, Integer> STROKE_ALPHA =
- new Property<PreviewBackground, Integer>(Integer.class, "strokeAlpha") {
- @Override
- public Integer get(PreviewBackground previewBackground) {
- return previewBackground.mStrokeAlpha;
- }
-
- @Override
- public void set(PreviewBackground previewBackground, Integer alpha) {
- previewBackground.mStrokeAlpha = alpha;
- previewBackground.invalidate();
- }
- };
-
- private static final Property<PreviewBackground, Integer> SHADOW_ALPHA =
- new Property<PreviewBackground, Integer>(Integer.class, "shadowAlpha") {
- @Override
- public Integer get(PreviewBackground previewBackground) {
- return previewBackground.mShadowAlpha;
- }
-
- @Override
- public void set(PreviewBackground previewBackground, Integer alpha) {
- previewBackground.mShadowAlpha = alpha;
- previewBackground.invalidate();
- }
- };
-
- public void setup(Launcher launcher, View invalidateDelegate,
- int availableSpace, int topPadding) {
- mInvalidateDelegate = invalidateDelegate;
- mBgColor = Themes.getAttrColor(launcher, android.R.attr.colorPrimary);
-
- DeviceProfile grid = launcher.getDeviceProfile();
- final int previewSize = grid.folderIconSizePx;
- final int previewPadding = grid.folderIconPreviewPadding;
-
- this.previewSize = (previewSize - 2 * previewPadding);
-
- basePreviewOffsetX = (availableSpace - this.previewSize) / 2;
- basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding;
-
- // Stroke width is 1dp
- mStrokeWidth = launcher.getResources().getDisplayMetrics().density;
-
- float radius = getScaledRadius();
- float shadowRadius = radius + mStrokeWidth;
- int shadowColor = Color.argb(SHADOW_OPACITY, 0, 0, 0);
- mShadowShader = new RadialGradient(0, 0, 1,
- new int[] {shadowColor, Color.TRANSPARENT},
- new float[] {radius / shadowRadius, 1},
- Shader.TileMode.CLAMP);
-
- invalidate();
- }
-
- int getRadius() {
- return previewSize / 2;
- }
-
- int getScaledRadius() {
- return (int) (mScale * getRadius());
- }
-
- int getOffsetX() {
- return basePreviewOffsetX - (getScaledRadius() - getRadius());
- }
-
- int getOffsetY() {
- return basePreviewOffsetY - (getScaledRadius() - getRadius());
- }
-
- /**
- * Returns the progress of the scale animation, where 0 means the scale is at 1f
- * and 1 means the scale is at ACCEPT_SCALE_FACTOR.
- */
- float getScaleProgress() {
- return (mScale - 1f) / (ACCEPT_SCALE_FACTOR - 1f);
- }
-
- void invalidate() {
- if (mInvalidateDelegate != null) {
- mInvalidateDelegate.invalidate();
- }
-
- if (mDrawingDelegate != null) {
- mDrawingDelegate.invalidate();
- }
- }
-
- void setInvalidateDelegate(View invalidateDelegate) {
- mInvalidateDelegate = invalidateDelegate;
- invalidate();
- }
-
- public void drawBackground(Canvas canvas) {
- mPaint.setStyle(Paint.Style.FILL);
- int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
- mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, alpha));
-
- drawCircle(canvas, 0 /* deltaRadius */);
-
- // Draw shadow.
- if (mShadowShader == null) {
- return;
- }
- float radius = getScaledRadius();
- float shadowRadius = radius + mStrokeWidth;
- mPaint.setColor(Color.BLACK);
- int offsetX = getOffsetX();
- int offsetY = getOffsetY();
- final int saveCount;
- if (canvas.isHardwareAccelerated()) {
- saveCount = canvas.saveLayer(offsetX - mStrokeWidth, offsetY,
- offsetX + radius + shadowRadius, offsetY + shadowRadius + shadowRadius,
- null, Canvas.CLIP_TO_LAYER_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
-
- } else {
- saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
- clipCanvasSoftware(canvas, Region.Op.DIFFERENCE);
- }
-
- mShaderMatrix.setScale(shadowRadius, shadowRadius);
- mShaderMatrix.postTranslate(radius + offsetX, shadowRadius + offsetY);
- mShadowShader.setLocalMatrix(mShaderMatrix);
- mPaint.setAlpha(mShadowAlpha);
- mPaint.setShader(mShadowShader);
- canvas.drawPaint(mPaint);
- mPaint.setAlpha(255);
- mPaint.setShader(null);
- if (canvas.isHardwareAccelerated()) {
- mPaint.setXfermode(mShadowPorterDuffXfermode);
- canvas.drawCircle(radius + offsetX, radius + offsetY, radius, mPaint);
- mPaint.setXfermode(null);
- }
-
- canvas.restoreToCount(saveCount);
- }
-
- public void fadeInBackgroundShadow() {
- if (mShadowAnimator != null) {
- mShadowAnimator.cancel();
- }
- mShadowAnimator = ObjectAnimator
- .ofInt(this, SHADOW_ALPHA, 0, 255)
- .setDuration(100);
- mShadowAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mShadowAnimator = null;
- }
- });
- mShadowAnimator.start();
- }
-
- public void animateBackgroundStroke() {
- if (mStrokeAlphaAnimator != null) {
- mStrokeAlphaAnimator.cancel();
- }
- mStrokeAlphaAnimator = ObjectAnimator
- .ofInt(this, STROKE_ALPHA, MAX_BG_OPACITY / 2, MAX_BG_OPACITY)
- .setDuration(100);
- mStrokeAlphaAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mStrokeAlphaAnimator = null;
- }
- });
- mStrokeAlphaAnimator.start();
- }
-
- public void drawBackgroundStroke(Canvas canvas) {
- mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, mStrokeAlpha));
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setStrokeWidth(mStrokeWidth);
- drawCircle(canvas, 1 /* deltaRadius */);
- }
-
- public void drawLeaveBehind(Canvas canvas) {
- float originalScale = mScale;
- mScale = 0.5f;
-
- mPaint.setStyle(Paint.Style.FILL);
- mPaint.setColor(Color.argb(160, 245, 245, 245));
- drawCircle(canvas, 0 /* deltaRadius */);
-
- mScale = originalScale;
- }
-
- private void drawCircle(Canvas canvas,float deltaRadius) {
- float radius = getScaledRadius();
- canvas.drawCircle(radius + getOffsetX(), radius + getOffsetY(),
- radius - deltaRadius, mPaint);
- }
-
- // It is the callers responsibility to save and restore the canvas layers.
- private void clipCanvasSoftware(Canvas canvas, Region.Op op) {
- mPath.reset();
- float r = getScaledRadius();
- mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW);
- canvas.clipPath(mPath, op);
- }
-
- // It is the callers responsibility to save and restore the canvas layers.
- private void clipCanvasHardware(Canvas canvas) {
- mPaint.setColor(Color.BLACK);
- mPaint.setXfermode(mClipPorterDuffXfermode);
-
- float radius = getScaledRadius();
- mShaderMatrix.setScale(radius, radius);
- mShaderMatrix.postTranslate(radius + getOffsetX(), radius + getOffsetY());
- mClipShader.setLocalMatrix(mShaderMatrix);
- mPaint.setShader(mClipShader);
- canvas.drawPaint(mPaint);
- mPaint.setXfermode(null);
- mPaint.setShader(null);
- }
-
- private void delegateDrawing(CellLayout delegate, int cellX, int cellY) {
- if (mDrawingDelegate != delegate) {
- delegate.addFolderBackground(this);
- }
-
- mDrawingDelegate = delegate;
- delegateCellX = cellX;
- delegateCellY = cellY;
-
- invalidate();
- }
-
- private void clearDrawingDelegate() {
- if (mDrawingDelegate != null) {
- mDrawingDelegate.removeFolderBackground(this);
- }
-
- mDrawingDelegate = null;
- invalidate();
- }
-
- private boolean drawingDelegated() {
- return mDrawingDelegate != null;
- }
-
- private void animateScale(float finalScale, float finalMultiplier,
- final Runnable onStart, final Runnable onEnd) {
- final float scale0 = mScale;
- final float scale1 = finalScale;
-
- final float bgMultiplier0 = mColorMultiplier;
- final float bgMultiplier1 = finalMultiplier;
-
- if (mScaleAnimator != null) {
- mScaleAnimator.cancel();
- }
-
- mScaleAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
-
- mScaleAnimator.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float prog = animation.getAnimatedFraction();
- mScale = prog * scale1 + (1 - prog) * scale0;
- mColorMultiplier = prog * bgMultiplier1 + (1 - prog) * bgMultiplier0;
- invalidate();
- }
- });
- mScaleAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- if (onStart != null) {
- onStart.run();
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (onEnd != null) {
- onEnd.run();
- }
- mScaleAnimator = null;
- }
- });
-
- mScaleAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
- mScaleAnimator.start();
- }
-
- public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) {
- Runnable onStart = new Runnable() {
- @Override
- public void run() {
- delegateDrawing(cl, cellX, cellY);
- }
- };
- animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null);
- }
-
- public void animateToRest() {
- // This can be called multiple times -- we need to make sure the drawing delegate
- // is saved and restored at the beginning of the animation, since cancelling the
- // existing animation can clear the delgate.
- final CellLayout cl = mDrawingDelegate;
- final int cellX = delegateCellX;
- final int cellY = delegateCellY;
-
- Runnable onStart = new Runnable() {
- @Override
- public void run() {
- delegateDrawing(cl, cellX, cellY);
- }
- };
- Runnable onEnd = new Runnable() {
- @Override
- public void run() {
- clearDrawingDelegate();
- }
- };
- animateScale(1f, 1f, onStart, onEnd);
- }
-
- public int getBackgroundAlpha() {
- return (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
- }
-
- public float getStrokeWidth() {
- return mStrokeWidth;
- }
- }
-
public void setFolderBackground(PreviewBackground bg) {
mBackground = bg;
mBackground.setInvalidateDelegate(this);
@@ -989,89 +546,14 @@
}
}
- class FolderPreviewItemAnim {
- ValueAnimator mValueAnimator;
- float finalScale;
- float finalTransX;
- float finalTransY;
-
- /**
- *
- * @param params layout params to animate
- * @param index0 original index of the item to be animated
- * @param nItems0 original number of items in the preview
- * @param index1 new index of the item to be animated
- * @param nItems1 new number of items in the preview
- * @param duration duration in ms of the animation
- * @param onCompleteRunnable runnable to execute upon animation completion
- */
- public FolderPreviewItemAnim(final PreviewItemDrawingParams params, int index0, int nItems0,
- int index1, int nItems1, int duration, final Runnable onCompleteRunnable) {
-
- computePreviewItemDrawingParams(index1, nItems1, mTmpParams);
-
- finalScale = mTmpParams.scale;
- finalTransX = mTmpParams.transX;
- finalTransY = mTmpParams.transY;
-
- computePreviewItemDrawingParams(index0, nItems0, mTmpParams);
-
- final float scale0 = mTmpParams.scale;
- final float transX0 = mTmpParams.transX;
- final float transY0 = mTmpParams.transY;
-
- mValueAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
- mValueAnimator.addUpdateListener(new AnimatorUpdateListener(){
- public void onAnimationUpdate(ValueAnimator animation) {
- float progress = animation.getAnimatedFraction();
-
- params.transX = transX0 + progress * (finalTransX - transX0);
- params.transY = transY0 + progress * (finalTransY - transY0);
- params.scale = scale0 + progress * (finalScale - scale0);
- invalidate();
- }
- });
-
- mValueAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
- params.anim = null;
- }
- });
- mValueAnimator.setDuration(duration);
- }
-
- public void start() {
- mValueAnimator.start();
- }
-
- public void cancel() {
- mValueAnimator.cancel();
- }
-
- public boolean hasEqualFinalState(FolderPreviewItemAnim anim) {
- return finalTransY == anim.finalTransY && finalTransX == anim.finalTransX &&
- finalScale == anim.finalScale;
-
- }
- }
-
private void animateFirstItem(final Drawable d, int duration, final boolean reverse,
final Runnable onCompleteRunnable) {
-
FolderPreviewItemAnim anim;
if (!reverse) {
- anim = new FolderPreviewItemAnim(mDrawingParams.get(0), -1, -1, 0, 2, duration,
+ anim = new FolderPreviewItemAnim(this, mDrawingParams.get(0), -1, -1, 0, 2, duration,
onCompleteRunnable);
} else {
- anim = new FolderPreviewItemAnim(mDrawingParams.get(0), 0, 2, -1, -1, duration,
+ anim = new FolderPreviewItemAnim(this, mDrawingParams.get(0), 0, 2, -1, -1, duration,
onCompleteRunnable);
}
anim.start();
@@ -1107,6 +589,16 @@
return itemsToDisplay;
}
+ @Override
+ protected boolean verifyDrawable(@NonNull Drawable who) {
+ for (int i = 0; i < mDrawingParams.size(); i++) {
+ if (mDrawingParams.get(i).drawable == who) {
+ return true;
+ }
+ }
+ return super.verifyDrawable(who);
+ }
+
private void updateItemDrawingParams(boolean animate) {
List<BubbleTextView> items = getItemsToDisplay();
int nItemsInPreview = items.size();
@@ -1125,13 +617,19 @@
PreviewItemDrawingParams p = mDrawingParams.get(i);
p.drawable = items.get(i).getCompoundDrawables()[1];
+ if (p.drawable != null && !mFolder.isOpen()) {
+ // Set the callback to FolderIcon as it is responsible to drawing the icon. The
+ // callback will be release when the folder is opened.
+ p.drawable.setCallback(this);
+ }
+
if (!animate || FeatureFlags.LAUNCHER3_LEGACY_FOLDER_ICON) {
computePreviewItemDrawingParams(i, nItemsInPreview, p);
if (mReferenceDrawable == null) {
mReferenceDrawable = p.drawable;
}
} else {
- FolderPreviewItemAnim anim = new FolderPreviewItemAnim(p, i, prevNumItems, i,
+ FolderPreviewItemAnim anim = new FolderPreviewItemAnim(this, p, i, prevNumItems, i,
nItemsInPreview, DROP_IN_ANIMATION_DURATION, null);
if (p.anim != null) {
@@ -1292,10 +790,10 @@
}
}
- public interface PreviewLayoutRule {
+ interface PreviewLayoutRule {
PreviewItemDrawingParams computePreviewItemDrawingParams(int index, int curNumItems,
PreviewItemDrawingParams params);
- void init(int availableSpace, int intrinsicIconSize, boolean rtl);
+ void init(int availableSpace, float intrinsicIconSize, boolean rtl);
float scaleForItem(int index, int totalNumItems);
float getIconSize();
int maxNumItems();
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 87e42eb..d0ac9f4 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +19,8 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -46,7 +48,6 @@
import com.android.launcher3.util.Thunk;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -72,7 +73,7 @@
private final LayoutInflater mInflater;
private final ViewGroupFocusHelper mFocusIndicatorHelper;
- @Thunk final HashMap<View, Runnable> mPendingAnimations = new HashMap<>();
+ @Thunk final ArrayMap<View, Runnable> mPendingAnimations = new ArrayMap<>();
@ViewDebug.ExportedProperty(category = "launcher")
private final int mMaxCountX;
@@ -111,7 +112,7 @@
public void setFolder(Folder folder) {
mFolder = folder;
mKeyListener = new PagedFolderKeyEventListener(folder);
- mPageIndicator = (PageIndicator) folder.findViewById(R.id.folder_page_indicator);
+ mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
initParentViews(folder);
}
@@ -180,21 +181,13 @@
super.dispatchDraw(canvas);
}
- public void onIconInvalidated(BubbleTextView icon) {
- FolderIcon folderIcon = mFolder.mFolderIcon;
- if (icon.getTag() instanceof ItemInfo
- && folderIcon.mPreviewVerifier.isItemInPreview(((ItemInfo) icon.getTag()).rank)) {
- folderIcon.invalidate();
- }
- }
-
/**
* Binds items to the layout.
* @return list of items that could not be bound, probably because we hit the max size limit.
*/
public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
- ArrayList<View> icons = new ArrayList<View>();
- ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
+ ArrayList<View> icons = new ArrayList<>();
+ ArrayList<ShortcutInfo> extra = new ArrayList<>();
for (ShortcutInfo item : items) {
if (!ALLOW_FOLDER_SCROLL && icons.size() >= mMaxItemsPerPage) {
@@ -328,7 +321,7 @@
@SuppressLint("RtlHardcoded")
private void arrangeChildren(ArrayList<View> list, int itemCount, boolean saveChanges) {
- ArrayList<CellLayout> pages = new ArrayList<CellLayout>();
+ ArrayList<CellLayout> pages = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
CellLayout page = (CellLayout) getChildAt(i);
page.removeAllViews();
@@ -535,7 +528,7 @@
*/
public void completePendingPageChanges() {
if (!mPendingAnimations.isEmpty()) {
- HashMap<View, Runnable> pendingViews = new HashMap<>(mPendingAnimations);
+ ArrayMap<View, Runnable> pendingViews = new ArrayMap<>(mPendingAnimations);
for (Map.Entry<View, Runnable> e : pendingViews.entrySet()) {
e.getKey().animate().cancel();
e.getValue().run();
@@ -564,7 +557,14 @@
if (page != null) {
ShortcutAndWidgetContainer parent = page.getShortcutsAndWidgets();
for (int i = parent.getChildCount() - 1; i >= 0; i--) {
- ((BubbleTextView) parent.getChildAt(i)).verifyHighRes();
+ BubbleTextView icon = ((BubbleTextView) parent.getChildAt(i));
+ icon.verifyHighRes();
+ // Set the callback back to the actual icon, in case
+ // it was captured by the FolderIcon
+ Drawable d = icon.getCompoundDrawables()[1];
+ if (d != null) {
+ d.setCallback(icon);
+ }
}
}
}
diff --git a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
new file mode 100644
index 0000000..0da7c5c
--- /dev/null
+++ b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
@@ -0,0 +1,97 @@
+/*
+ * 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.folder;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+
+import com.android.launcher3.LauncherAnimUtils;
+
+/**
+ * Animates a Folder preview item.
+ */
+class FolderPreviewItemAnim {
+ private ValueAnimator mValueAnimator;
+
+ float finalScale;
+ float finalTransX;
+ float finalTransY;
+
+ private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+
+ /**
+ * @param folderIcon The FolderIcon this preview will be drawn in.
+ * @param params layout params to animate
+ * @param index0 original index of the item to be animated
+ * @param items0 original number of items in the preview
+ * @param index1 new index of the item to be animated
+ * @param items1 new number of items in the preview
+ * @param duration duration in ms of the animation
+ * @param onCompleteRunnable runnable to execute upon animation completion
+ */
+ FolderPreviewItemAnim(final FolderIcon folderIcon, final PreviewItemDrawingParams params,
+ int index0, int items0, int index1, int items1, int duration,
+ final Runnable onCompleteRunnable) {
+ folderIcon.computePreviewItemDrawingParams(index1, items1, mTmpParams);
+
+ finalScale = mTmpParams.scale;
+ finalTransX = mTmpParams.transX;
+ finalTransY = mTmpParams.transY;
+
+ folderIcon.computePreviewItemDrawingParams(index0, items0, mTmpParams);
+
+ final float scale0 = mTmpParams.scale;
+ final float transX0 = mTmpParams.transX;
+ final float transY0 = mTmpParams.transY;
+
+ mValueAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
+ mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float progress = animation.getAnimatedFraction();
+
+ params.transX = transX0 + progress * (finalTransX - transX0);
+ params.transY = transY0 + progress * (finalTransY - transY0);
+ params.scale = scale0 + progress * (finalScale - scale0);
+ folderIcon.invalidate();
+ }
+ });
+ mValueAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
+ params.anim = null;
+ }
+ });
+ mValueAnimator.setDuration(duration);
+ }
+
+ public void start() {
+ mValueAnimator.start();
+ }
+
+ public void cancel() {
+ mValueAnimator.cancel();
+ }
+
+ public boolean hasEqualFinalState(FolderPreviewItemAnim anim) {
+ return finalTransY == anim.finalTransY && finalTransX == anim.finalTransX &&
+ finalScale == anim.finalScale;
+
+ }
+}
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
new file mode 100644
index 0000000..44ebbcd
--- /dev/null
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -0,0 +1,430 @@
+/*
+ * 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.folder;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RadialGradient;
+import android.graphics.Region;
+import android.graphics.Shader;
+import android.support.v4.graphics.ColorUtils;
+import android.util.Property;
+import android.view.View;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.util.Themes;
+
+/**
+ * This object represents a FolderIcon preview background. It stores drawing / measurement
+ * information, handles drawing, and animation (accept state <--> rest state).
+ */
+public class PreviewBackground {
+
+ private static final int CONSUMPTION_ANIMATION_DURATION = 100;
+
+ private final PorterDuffXfermode mClipPorterDuffXfermode
+ = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
+ // Create a RadialGradient such that it draws a black circle and then extends with
+ // transparent. To achieve this, we keep the gradient to black for the range [0, 1) and
+ // just at the edge quickly change it to transparent.
+ private final RadialGradient mClipShader = new RadialGradient(0, 0, 1,
+ new int[] {Color.BLACK, Color.BLACK, Color.TRANSPARENT },
+ new float[] {0, 0.999f, 1},
+ Shader.TileMode.CLAMP);
+
+ private final PorterDuffXfermode mShadowPorterDuffXfermode
+ = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
+ private RadialGradient mShadowShader = null;
+
+ private final Matrix mShaderMatrix = new Matrix();
+ private final Path mPath = new Path();
+
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ float mScale = 1f;
+ private float mColorMultiplier = 1f;
+ private int mBgColor;
+ private float mStrokeWidth;
+ private int mStrokeAlpha = MAX_BG_OPACITY;
+ private int mShadowAlpha = 255;
+ private View mInvalidateDelegate;
+
+ int previewSize;
+ int basePreviewOffsetX;
+ int basePreviewOffsetY;
+
+ private CellLayout mDrawingDelegate;
+ public int delegateCellX;
+ public int delegateCellY;
+
+ // When the PreviewBackground is drawn under an icon (for creating a folder) the border
+ // should not occlude the icon
+ public boolean isClipping = true;
+
+ // Drawing / animation configurations
+ private static final float ACCEPT_SCALE_FACTOR = 1.25f;
+ private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
+
+ // Expressed on a scale from 0 to 255.
+ private static final int BG_OPACITY = 160;
+ private static final int MAX_BG_OPACITY = 225;
+ private static final int SHADOW_OPACITY = 40;
+
+ private ValueAnimator mScaleAnimator;
+ private ObjectAnimator mStrokeAlphaAnimator;
+ private ObjectAnimator mShadowAnimator;
+
+ private static final Property<PreviewBackground, Integer> STROKE_ALPHA =
+ new Property<PreviewBackground, Integer>(Integer.class, "strokeAlpha") {
+ @Override
+ public Integer get(PreviewBackground previewBackground) {
+ return previewBackground.mStrokeAlpha;
+ }
+
+ @Override
+ public void set(PreviewBackground previewBackground, Integer alpha) {
+ previewBackground.mStrokeAlpha = alpha;
+ previewBackground.invalidate();
+ }
+ };
+
+ private static final Property<PreviewBackground, Integer> SHADOW_ALPHA =
+ new Property<PreviewBackground, Integer>(Integer.class, "shadowAlpha") {
+ @Override
+ public Integer get(PreviewBackground previewBackground) {
+ return previewBackground.mShadowAlpha;
+ }
+
+ @Override
+ public void set(PreviewBackground previewBackground, Integer alpha) {
+ previewBackground.mShadowAlpha = alpha;
+ previewBackground.invalidate();
+ }
+ };
+
+ public void setup(Launcher launcher, View invalidateDelegate,
+ int availableSpace, int topPadding) {
+ mInvalidateDelegate = invalidateDelegate;
+ mBgColor = Themes.getAttrColor(launcher, android.R.attr.colorPrimary);
+
+ DeviceProfile grid = launcher.getDeviceProfile();
+ final int previewSize = grid.folderIconSizePx;
+ final int previewPadding = grid.folderIconPreviewPadding;
+
+ this.previewSize = (previewSize - 2 * previewPadding);
+
+ basePreviewOffsetX = (availableSpace - this.previewSize) / 2;
+ basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding;
+
+ // Stroke width is 1dp
+ mStrokeWidth = launcher.getResources().getDisplayMetrics().density;
+
+ float radius = getScaledRadius();
+ float shadowRadius = radius + mStrokeWidth;
+ int shadowColor = Color.argb(SHADOW_OPACITY, 0, 0, 0);
+ mShadowShader = new RadialGradient(0, 0, 1,
+ new int[] {shadowColor, Color.TRANSPARENT},
+ new float[] {radius / shadowRadius, 1},
+ Shader.TileMode.CLAMP);
+
+ invalidate();
+ }
+
+ int getRadius() {
+ return previewSize / 2;
+ }
+
+ int getScaledRadius() {
+ return (int) (mScale * getRadius());
+ }
+
+ int getOffsetX() {
+ return basePreviewOffsetX - (getScaledRadius() - getRadius());
+ }
+
+ int getOffsetY() {
+ return basePreviewOffsetY - (getScaledRadius() - getRadius());
+ }
+
+ /**
+ * Returns the progress of the scale animation, where 0 means the scale is at 1f
+ * and 1 means the scale is at ACCEPT_SCALE_FACTOR.
+ */
+ float getScaleProgress() {
+ return (mScale - 1f) / (ACCEPT_SCALE_FACTOR - 1f);
+ }
+
+ void invalidate() {
+ if (mInvalidateDelegate != null) {
+ mInvalidateDelegate.invalidate();
+ }
+
+ if (mDrawingDelegate != null) {
+ mDrawingDelegate.invalidate();
+ }
+ }
+
+ void setInvalidateDelegate(View invalidateDelegate) {
+ mInvalidateDelegate = invalidateDelegate;
+ invalidate();
+ }
+
+ public void drawBackground(Canvas canvas) {
+ mPaint.setStyle(Paint.Style.FILL);
+ int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
+ mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, alpha));
+
+ drawCircle(canvas, 0 /* deltaRadius */);
+
+ // Draw shadow.
+ if (mShadowShader == null) {
+ return;
+ }
+ float radius = getScaledRadius();
+ float shadowRadius = radius + mStrokeWidth;
+ mPaint.setColor(Color.BLACK);
+ int offsetX = getOffsetX();
+ int offsetY = getOffsetY();
+ final int saveCount;
+ if (canvas.isHardwareAccelerated()) {
+ saveCount = canvas.saveLayer(offsetX - mStrokeWidth, offsetY,
+ offsetX + radius + shadowRadius, offsetY + shadowRadius + shadowRadius,
+ null, Canvas.CLIP_TO_LAYER_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
+
+ } else {
+ saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
+ clipCanvasSoftware(canvas, Region.Op.DIFFERENCE);
+ }
+
+ mShaderMatrix.setScale(shadowRadius, shadowRadius);
+ mShaderMatrix.postTranslate(radius + offsetX, shadowRadius + offsetY);
+ mShadowShader.setLocalMatrix(mShaderMatrix);
+ mPaint.setAlpha(mShadowAlpha);
+ mPaint.setShader(mShadowShader);
+ canvas.drawPaint(mPaint);
+ mPaint.setAlpha(255);
+ mPaint.setShader(null);
+ if (canvas.isHardwareAccelerated()) {
+ mPaint.setXfermode(mShadowPorterDuffXfermode);
+ canvas.drawCircle(radius + offsetX, radius + offsetY, radius, mPaint);
+ mPaint.setXfermode(null);
+ }
+
+ canvas.restoreToCount(saveCount);
+ }
+
+ public void fadeInBackgroundShadow() {
+ if (mShadowAnimator != null) {
+ mShadowAnimator.cancel();
+ }
+ mShadowAnimator = ObjectAnimator
+ .ofInt(this, SHADOW_ALPHA, 0, 255)
+ .setDuration(100);
+ mShadowAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mShadowAnimator = null;
+ }
+ });
+ mShadowAnimator.start();
+ }
+
+ public void animateBackgroundStroke() {
+ if (mStrokeAlphaAnimator != null) {
+ mStrokeAlphaAnimator.cancel();
+ }
+ mStrokeAlphaAnimator = ObjectAnimator
+ .ofInt(this, STROKE_ALPHA, MAX_BG_OPACITY / 2, MAX_BG_OPACITY)
+ .setDuration(100);
+ mStrokeAlphaAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStrokeAlphaAnimator = null;
+ }
+ });
+ mStrokeAlphaAnimator.start();
+ }
+
+ public void drawBackgroundStroke(Canvas canvas) {
+ mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, mStrokeAlpha));
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setStrokeWidth(mStrokeWidth);
+ drawCircle(canvas, 1 /* deltaRadius */);
+ }
+
+ public void drawLeaveBehind(Canvas canvas) {
+ float originalScale = mScale;
+ mScale = 0.5f;
+
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setColor(Color.argb(160, 245, 245, 245));
+ drawCircle(canvas, 0 /* deltaRadius */);
+
+ mScale = originalScale;
+ }
+
+ private void drawCircle(Canvas canvas,float deltaRadius) {
+ float radius = getScaledRadius();
+ canvas.drawCircle(radius + getOffsetX(), radius + getOffsetY(),
+ radius - deltaRadius, mPaint);
+ }
+
+ // It is the callers responsibility to save and restore the canvas layers.
+ void clipCanvasSoftware(Canvas canvas, Region.Op op) {
+ mPath.reset();
+ float r = getScaledRadius();
+ mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW);
+ canvas.clipPath(mPath, op);
+ }
+
+ // It is the callers responsibility to save and restore the canvas layers.
+ void clipCanvasHardware(Canvas canvas) {
+ mPaint.setColor(Color.BLACK);
+ mPaint.setXfermode(mClipPorterDuffXfermode);
+
+ float radius = getScaledRadius();
+ mShaderMatrix.setScale(radius, radius);
+ mShaderMatrix.postTranslate(radius + getOffsetX(), radius + getOffsetY());
+ mClipShader.setLocalMatrix(mShaderMatrix);
+ mPaint.setShader(mClipShader);
+ canvas.drawPaint(mPaint);
+ mPaint.setXfermode(null);
+ mPaint.setShader(null);
+ }
+
+ private void delegateDrawing(CellLayout delegate, int cellX, int cellY) {
+ if (mDrawingDelegate != delegate) {
+ delegate.addFolderBackground(this);
+ }
+
+ mDrawingDelegate = delegate;
+ delegateCellX = cellX;
+ delegateCellY = cellY;
+
+ invalidate();
+ }
+
+ private void clearDrawingDelegate() {
+ if (mDrawingDelegate != null) {
+ mDrawingDelegate.removeFolderBackground(this);
+ }
+
+ mDrawingDelegate = null;
+ invalidate();
+ }
+
+ boolean drawingDelegated() {
+ return mDrawingDelegate != null;
+ }
+
+ private void animateScale(float finalScale, float finalMultiplier,
+ final Runnable onStart, final Runnable onEnd) {
+ final float scale0 = mScale;
+ final float scale1 = finalScale;
+
+ final float bgMultiplier0 = mColorMultiplier;
+ final float bgMultiplier1 = finalMultiplier;
+
+ if (mScaleAnimator != null) {
+ mScaleAnimator.cancel();
+ }
+
+ mScaleAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
+
+ mScaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float prog = animation.getAnimatedFraction();
+ mScale = prog * scale1 + (1 - prog) * scale0;
+ mColorMultiplier = prog * bgMultiplier1 + (1 - prog) * bgMultiplier0;
+ invalidate();
+ }
+ });
+ mScaleAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (onStart != null) {
+ onStart.run();
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (onEnd != null) {
+ onEnd.run();
+ }
+ mScaleAnimator = null;
+ }
+ });
+
+ mScaleAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION);
+ mScaleAnimator.start();
+ }
+
+ public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) {
+ Runnable onStart = new Runnable() {
+ @Override
+ public void run() {
+ delegateDrawing(cl, cellX, cellY);
+ }
+ };
+ animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null);
+ }
+
+ public void animateToRest() {
+ // This can be called multiple times -- we need to make sure the drawing delegate
+ // is saved and restored at the beginning of the animation, since cancelling the
+ // existing animation can clear the delgate.
+ final CellLayout cl = mDrawingDelegate;
+ final int cellX = delegateCellX;
+ final int cellY = delegateCellY;
+
+ Runnable onStart = new Runnable() {
+ @Override
+ public void run() {
+ delegateDrawing(cl, cellX, cellY);
+ }
+ };
+ Runnable onEnd = new Runnable() {
+ @Override
+ public void run() {
+ clearDrawingDelegate();
+ }
+ };
+ animateScale(1f, 1f, onStart, onEnd);
+ }
+
+ public int getBackgroundAlpha() {
+ return (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier);
+ }
+
+ public float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+}
diff --git a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
new file mode 100644
index 0000000..607b7ca
--- /dev/null
+++ b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
@@ -0,0 +1,54 @@
+/*
+ * 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.folder;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Manages the parameters used to draw a Folder preview item.
+ */
+class PreviewItemDrawingParams {
+ float transX;
+ float transY;
+ float scale;
+ float overlayAlpha;
+ FolderPreviewItemAnim anim;
+ public boolean hidden;
+ Drawable drawable;
+
+ PreviewItemDrawingParams(float transX, float transY, float scale, float overlayAlpha) {
+ this.transX = transX;
+ this.transY = transY;
+ this.scale = scale;
+ this.overlayAlpha = overlayAlpha;
+ }
+
+ public void update(float transX, float transY, float scale) {
+ // We ensure the update will not interfere with an animation on the layout params
+ // If the final values differ, we cancel the animation.
+ if (anim != null) {
+ if (anim.finalTransX == transX || anim.finalTransY == transY
+ || anim.finalScale == scale) {
+ return;
+ }
+ anim.cancel();
+ }
+
+ this.transX = transX;
+ this.transY = transY;
+ this.scale = scale;
+ }
+}
diff --git a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
index 12bca5f..138dc1c 100644
--- a/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/StackFolderIconLayoutRule.java
@@ -16,8 +16,6 @@
package com.android.launcher3.folder;
-import com.android.launcher3.folder.FolderIcon.PreviewItemDrawingParams;
-
public class StackFolderIconLayoutRule implements FolderIcon.PreviewLayoutRule {
static final int MAX_NUM_ITEMS_IN_PREVIEW = 3;
@@ -35,7 +33,7 @@
private float mMaxPerspectiveShift;
@Override
- public void init(int availableSpace, int intrinsicIconSize, boolean rtl) {
+ public void init(int availableSpace, float intrinsicIconSize, boolean rtl) {
mAvailableSpaceInPreview = availableSpace;
// cos(45) = 0.707 + ~= 0.1) = 0.8f
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 492d853..10e91c0 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -23,12 +23,11 @@
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.view.View;
-import android.widget.TextView;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetHostView;
import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
@@ -57,8 +56,8 @@
blurSizeOutline =
context.getResources().getDimensionPixelSize(R.dimen.blur_size_medium_outline);
- if (mView instanceof TextView) {
- Drawable d = Workspace.getTextViewIcon((TextView) mView);
+ if (mView instanceof BubbleTextView) {
+ Drawable d = ((BubbleTextView) mView).getIcon();
Rect bounds = getDrawableBounds(d);
previewPadding = blurSizeOutline - bounds.left - bounds.top;
} else {
@@ -71,8 +70,8 @@
*/
private void drawDragView(Canvas destCanvas) {
destCanvas.save();
- if (mView instanceof TextView) {
- Drawable d = Workspace.getTextViewIcon((TextView) mView);
+ if (mView instanceof BubbleTextView) {
+ Drawable d = ((BubbleTextView) mView).getIcon();
Rect bounds = getDrawableBounds(d);
destCanvas.translate(blurSizeOutline / 2 - bounds.left,
blurSizeOutline / 2 - bounds.top);
@@ -112,8 +111,8 @@
int width = mView.getWidth();
int height = mView.getHeight();
- if (mView instanceof TextView) {
- Drawable d = Workspace.getTextViewIcon((TextView) mView);
+ if (mView instanceof BubbleTextView) {
+ Drawable d = ((BubbleTextView) mView).getIcon();
Rect bounds = getDrawableBounds(d);
width = bounds.width();
height = bounds.height();
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 19e57024..830ca82 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -322,14 +322,16 @@
IconCache cache = app.getIconCache();
Bitmap unbadgedBitmap = unbadgedDrawable == null
? cache.getDefaultIcon(Process.myUserHandle())
- : LauncherIcons.createScaledBitmapWithoutShadow(unbadgedDrawable, context,
- Build.VERSION_CODES.O);
+ : LauncherIcons.createScaledBitmapWithoutShadow(unbadgedDrawable, context, 0);
if (!badged) {
return unbadgedBitmap;
}
unbadgedBitmap = LauncherIcons.addShadowToIcon(unbadgedBitmap, context);
+ return badgeWithBitmap(unbadgedBitmap, getShortcutInfoBadge(shortcutInfo, cache), context);
+ }
+ public static Bitmap getShortcutInfoBadge(ShortcutInfoCompat shortcutInfo, IconCache cache) {
final Bitmap badgeBitmap;
ComponentName cn = shortcutInfo.getActivity();
if (cn != null) {
@@ -347,7 +349,7 @@
cache.getTitleAndIconForApp(pkgInfo, false);
badgeBitmap = pkgInfo.iconBitmap;
}
- return badgeWithBitmap(unbadgedBitmap, badgeBitmap, context);
+ return badgeBitmap;
}
/**
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index deb5b63..06dc7ac 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -178,7 +178,7 @@
Rect bounds = getBounds();
canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY());
- drawInternal(canvas);
+ super.draw(canvas);
canvas.restoreToCount(saveCount);
}
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 8dca699..baaa66a 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -16,25 +16,25 @@
package com.android.launcher3.notification;
+import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationChannel;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.annotation.Nullable;
-import android.support.v4.util.Pair;
import android.text.TextUtils;
-
+import android.util.ArraySet;
+import android.util.Pair;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageUserKey;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -44,6 +44,7 @@
* as well and when this service first connects. An instance of NotificationListener,
* and its methods for getting notifications, can be obtained via {@link #getInstanceIfConnected()}.
*/
+@TargetApi(Build.VERSION_CODES.O)
public class NotificationListener extends NotificationListenerService {
private static final int MSG_NOTIFICATION_POSTED = 1;
@@ -57,9 +58,9 @@
private final Handler mWorkerHandler;
private final Handler mUiHandler;
- private Ranking mTempRanking = new Ranking();
+ private final Ranking mTempRanking = new Ranking();
- private Handler.Callback mWorkerCallback = new Handler.Callback() {
+ private final Handler.Callback mWorkerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
@@ -80,7 +81,7 @@
}
};
- private Handler.Callback mUiCallback = new Handler.Callback() {
+ private final Handler.Callback mUiCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
@@ -163,9 +164,9 @@
* An object containing data to send to MSG_NOTIFICATION_POSTED targets.
*/
private class NotificationPostedMsg {
- PackageUserKey packageUserKey;
- NotificationKeyData notificationKey;
- boolean shouldBeFilteredOut;
+ final PackageUserKey packageUserKey;
+ final NotificationKeyData notificationKey;
+ final boolean shouldBeFilteredOut;
NotificationPostedMsg(StatusBarNotification sbn) {
packageUserKey = PackageUserKey.fromNotification(sbn);
@@ -189,7 +190,8 @@
StatusBarNotification[] notifications = NotificationListener.this
.getActiveNotifications(NotificationKeyData.extractKeysOnly(keys)
.toArray(new String[keys.size()]));
- return notifications == null ? Collections.EMPTY_LIST : Arrays.asList(notifications);
+ return notifications == null
+ ? Collections.<StatusBarNotification>emptyList() : Arrays.asList(notifications);
}
/**
@@ -201,7 +203,7 @@
private List<StatusBarNotification> filterNotifications(
StatusBarNotification[] notifications) {
if (notifications == null) return null;
- Set<Integer> removedNotifications = new HashSet<>();
+ Set<Integer> removedNotifications = new ArraySet<>();
for (int i = 0; i < notifications.length; i++) {
if (shouldBeFilteredOut(notifications[i])) {
removedNotifications.add(i);
diff --git a/src/com/android/launcher3/notification/SwipeHelper.java b/src/com/android/launcher3/notification/SwipeHelper.java
index 5f03252..ebbe5fc 100644
--- a/src/com/android/launcher3/notification/SwipeHelper.java
+++ b/src/com/android/launcher3/notification/SwipeHelper.java
@@ -24,23 +24,20 @@
import android.content.Context;
import android.graphics.RectF;
import android.os.Handler;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
-
import com.android.launcher3.R;
-import java.util.HashMap;
-
/**
* This class was copied from com.android.systemui.
*/
public class SwipeHelper {
- static final String TAG = "SwipeHelper";
- private static final boolean DEBUG = false;
+ private static final String TAG = "SwipeHelper";
private static final boolean DEBUG_INVALIDATE = false;
private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
private static final boolean CONSTRAIN_SWIPE = true;
@@ -50,10 +47,10 @@
public static final int X = 0;
public static final int Y = 1;
- private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
- private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
- private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
- private int MAX_DISMISS_VELOCITY = 4000; // dp/sec
+ private static final float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
+ private static final int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
+ private static final int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
+ private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec
private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width
@@ -61,12 +58,12 @@
private float mMinSwipeProgress = 0f;
private float mMaxSwipeProgress = 1f;
- private FlingAnimationUtils mFlingAnimationUtils;
+ private final FlingAnimationUtils mFlingAnimationUtils;
private float mPagingTouchSlop;
- private Callback mCallback;
- private Handler mHandler;
- private int mSwipeDirection;
- private VelocityTracker mVelocityTracker;
+ private final Callback mCallback;
+ private final Handler mHandler;
+ private final int mSwipeDirection;
+ private final VelocityTracker mVelocityTracker;
private float mInitialTouchPos;
private float mPerpendicularInitialTouchPos;
@@ -80,14 +77,14 @@
private boolean mLongPressSent;
private LongPressListener mLongPressListener;
private Runnable mWatchLongPress;
- private long mLongPressTimeout;
+ private final long mLongPressTimeout;
final private int[] mTmpPos = new int[2];
- private int mFalsingThreshold;
+ private final int mFalsingThreshold;
private boolean mTouchAboveFalsingThreshold;
private boolean mDisableHwLayers;
- private HashMap<View, Animator> mDismissPendingMap = new HashMap<>();
+ private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
public SwipeHelper(int swipeDirection, Callback callback, Context context) {
mCallback = callback;
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index c5daca0..77375fa 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -459,7 +459,9 @@
x += mIsLeftAligned ? xOffset : -xOffset;
// Open above icon if there is room.
- int iconHeight = icon.getIcon().getBounds().height();
+ int iconHeight = icon.getIcon() != null
+ ? icon.getIcon().getBounds().height()
+ : icon.getHeight();
int y = mTempRect.top + icon.getPaddingTop() - height;
mIsAboveIcon = y > dragLayer.getTop() + insets.top;
if (!mIsAboveIcon) {
diff --git a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
index 59a0386..8785a56 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutsItemView.java
@@ -104,8 +104,8 @@
@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 not the correct view
+ if (!(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)
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
new file mode 100644
index 0000000..9c8457a
--- /dev/null
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -0,0 +1,97 @@
+/*
+ * 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.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Region;
+import android.util.AttributeSet;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+
+/**
+ * Extension of {@link BubbleTextView} which draws two shadows on the text (ambient and key shadows}
+ */
+public class DoubleShadowBubbleTextView extends BubbleTextView {
+
+ private final ShadowInfo mShadowInfo;
+
+ public DoubleShadowBubbleTextView(Context context) {
+ this(context, null);
+ }
+
+ public DoubleShadowBubbleTextView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DoubleShadowBubbleTextView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mShadowInfo = new ShadowInfo(context, attrs, defStyle);
+ setShadowLayer(mShadowInfo.ambientShadowBlur, 0, 0, mShadowInfo.ambientShadowColor);
+ }
+ @Override
+ public void onDraw(Canvas canvas) {
+ // If text is transparent, don't draw any shadow
+ if ((getCurrentTextColor() >> 24) == 0) {
+ getPaint().clearShadowLayer();
+ super.onDraw(canvas);
+ return;
+ }
+
+ // We enhance the shadow by drawing the shadow twice
+ getPaint().setShadowLayer(
+ mShadowInfo.ambientShadowBlur, 0, 0, mShadowInfo.ambientShadowColor);
+
+ drawWithoutBadge(canvas);
+ canvas.save(Canvas.CLIP_SAVE_FLAG);
+ canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
+ getScrollX() + getWidth(),
+ getScrollY() + getHeight(), Region.Op.INTERSECT);
+
+ getPaint().setShadowLayer(mShadowInfo.keyShadowBlur, 0.0f,
+ mShadowInfo.keyShadowOffset, mShadowInfo.keyShadowColor);
+ drawWithoutBadge(canvas);
+ canvas.restore();
+
+ drawBadgeIfNecessary(canvas);
+ }
+
+ public static class ShadowInfo {
+ public final float ambientShadowBlur;
+ public final int ambientShadowColor;
+
+ public final float keyShadowBlur;
+ public final float keyShadowOffset;
+ public final int keyShadowColor;
+
+ public ShadowInfo(Context c, AttributeSet attrs, int defStyle) {
+
+ TypedArray a = c.obtainStyledAttributes(
+ attrs, R.styleable.ShadowInfo, defStyle, 0);
+
+ ambientShadowBlur = a.getDimension(R.styleable.ShadowInfo_ambientShadowBlur, 0);
+ ambientShadowColor = a.getColor(R.styleable.ShadowInfo_ambientShadowColor, 0);
+
+ keyShadowBlur = a.getDimension(R.styleable.ShadowInfo_keyShadowBlur, 0);
+ keyShadowOffset = a.getDimension(R.styleable.ShadowInfo_keyShadowOffset, 0);
+ keyShadowColor = a.getColor(R.styleable.ShadowInfo_keyShadowColor, 0);
+ a.recycle();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 6628971..19be28d 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -116,7 +116,7 @@
} else {
PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache());
- preview = LauncherIcons.createScaledBitmapWithoutShadow(icon, launcher, Build.VERSION_CODES.O);
+ preview = LauncherIcons.createScaledBitmapWithoutShadow(icon, launcher, 0);
mAddInfo.spanX = mAddInfo.spanY = 1;
scale = ((float) launcher.getDeviceProfile().iconSizePx) / preview.getWidth();
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 4055c3f..fff3472 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -21,13 +21,13 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
-import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.TextView;
@@ -80,7 +80,8 @@
setWillNotDraw(false);
mLauncher = Launcher.getLauncher(context);
mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
- mFastOutSlowInInterpolator = new FastOutSlowInInterpolator();
+ mFastOutSlowInInterpolator =
+ AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
mScrollInterpolator = new VerticalPullDetector.ScrollInterpolator();
mInsets = new Rect();
mVerticalPullDetector = new VerticalPullDetector(context);
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 4e296bf..14a9d17 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -139,8 +139,6 @@
if (LOGD) {
Log.d(TAG, String.format("onLongClick [v=%s]", v));
}
- // Return early if this is not initiated from a touch
- if (!v.isInTouchMode()) return false;
// When we are in transition, disregard long clicks
if (mLauncher.getWorkspace().isSwitchingState()) return false;
// Return if global dragging is not enabled
diff --git a/tests/src/com/android/launcher3/util/TestLauncherProvider.java b/tests/src/com/android/launcher3/util/TestLauncherProvider.java
index 6ca2121..1d6c18b 100644
--- a/tests/src/com/android/launcher3/util/TestLauncherProvider.java
+++ b/tests/src/com/android/launcher3/util/TestLauncherProvider.java
@@ -1,6 +1,7 @@
package com.android.launcher3.util;
import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.android.launcher3.LauncherProvider;
@@ -43,5 +44,8 @@
@Override
protected void onEmptyDbCreated() { }
+
+ @Override
+ protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { }
}
}
\ No newline at end of file