Merge "Centered all apps search text" into ub-launcher3-calgary
diff --git a/res/drawable/bg_white_pill.xml b/res/drawable/bg_white_pill.xml
index 29c3145..186b06b 100644
--- a/res/drawable/bg_white_pill.xml
+++ b/res/drawable/bg_white_pill.xml
@@ -17,6 +17,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/quantum_panel_bg_color" />
- <size android:height="48dp" />
- <corners android:radius="24dp" />
+ <corners android:radius="@dimen/bg_pill_radius" />
</shape>
\ No newline at end of file
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 632aff0..5c1fec7 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -44,7 +44,8 @@
android:id="@+id/hotseat"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="right" />
+ android:layout_gravity="right"
+ launcher:layout_ignoreInsets="true" />
<include
android:id="@+id/drop_target_bar"
@@ -56,7 +57,7 @@
<com.android.launcher3.pageindicators.PageIndicatorCaretLandscape
android:id="@+id/page_indicator"
- android:layout_width="48dp"
+ android:layout_width="@dimen/dynamic_grid_page_indicator_height"
android:layout_height="@dimen/dynamic_grid_page_indicator_height"
android:layout_gravity="bottom|left"/>
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 0321631..b394fa8 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -45,7 +45,8 @@
<include layout="@layout/hotseat"
android:id="@+id/hotseat"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ launcher:layout_ignoreInsets="true" />
<include layout="@layout/overview_panel"
android:id="@+id/overview_panel"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 86544d3..b59c715 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -44,7 +44,8 @@
<include layout="@layout/hotseat"
android:id="@+id/hotseat"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ launcher:layout_ignoreInsets="true" />
<include
android:id="@+id/drop_target_bar"
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index ad1fa82..822c8b6 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -22,8 +22,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:paddingBottom="@dimen/container_bounds_inset"
- android:paddingTop="@dimen/container_bounds_inset"
launcher:revealBackground="@drawable/quantum_panel_shape">
<View
@@ -62,12 +60,10 @@
android:layout_width="match_parent"
android:layout_height="@dimen/all_apps_search_bar_height"
android:layout_gravity="center|top"
- android:paddingLeft="@dimen/container_fastscroll_thumb_max_width"
- android:paddingRight="@dimen/container_fastscroll_thumb_max_width"
+ android:paddingTop="@dimen/all_apps_search_bar_margin_top"
android:gravity="center|bottom"
android:orientation="horizontal"
- android:saveEnabled="false"
- android:paddingTop="@dimen/all_apps_search_bar_margin_top" >
+ android:saveEnabled="false">
<TextView
android:layout_width="wrap_content"
@@ -87,13 +83,14 @@
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:focusableInTouchMode="true"
- android:gravity="start|center_vertical"
+ android:gravity="center"
android:imeOptions="actionSearch|flagNoExtractUi"
android:inputType="text|textNoSuggestions|textCapWords"
android:maxLines="1"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="#4c4c4c"
+ android:contentDescription="@string/all_apps_search_bar_hint"
android:textColorHint="@drawable/all_apps_search_hint"
android:textSize="16sp" />
</FrameLayout>
diff --git a/res/layout/all_apps_icon.xml b/res/layout/all_apps_icon.xml
index 3836fed..3d4bef7 100644
--- a/res/layout/all_apps_icon.xml
+++ b/res/layout/all_apps_icon.xml
@@ -21,8 +21,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:paddingTop="@dimen/all_apps_icon_top_bottom_padding"
- android:paddingBottom="@dimen/all_apps_icon_top_bottom_padding"
android:focusable="true"
- launcher:iconDisplay="all_apps" />
+ launcher:iconDisplay="all_apps"
+ launcher:centerVertically="true" />
diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml
index b879235..0895460 100644
--- a/res/layout/deep_shortcut.xml
+++ b/res/layout/deep_shortcut.xml
@@ -16,5 +16,13 @@
<com.android.launcher3.shortcuts.DeepShortcutView
xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/Icon.DeepShortcut"
- android:focusable="true"/>
+ android:layout_width="@dimen/bg_pill_width"
+ android:layout_height="@dimen/bg_pill_height"
+ android:elevation="@dimen/deep_shortcuts_elevation"
+ android:background="@drawable/bg_white_pill">
+
+ <com.android.launcher3.BubbleTextView
+ android:id="@+id/deep_shortcut"
+ style="@style/Icon.DeepShortcut"
+ android:focusable="true"/>
+</com.android.launcher3.shortcuts.DeepShortcutView>
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
index 74f7ca1..c4431be 100644
--- a/res/layout/widgets_view.xml
+++ b/res/layout/widgets_view.xml
@@ -22,8 +22,6 @@
android:id="@+id/widgets_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="@dimen/container_bounds_inset"
- android:paddingBottom="@dimen/container_bounds_inset"
android:descendantFocusability="afterDescendants"
launcher:revealBackground="@drawable/quantum_panel_shape_dark"
android:theme="@style/WidgetContainerTheme">
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index 1f97d24..0000000
--- a/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<resources>
-<!-- Container -->
- <dimen name="container_max_width">736dp</dimen>
-</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 85a436c..2838088 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -15,21 +15,15 @@
-->
<resources>
-<!-- Container -->
- <dimen name="container_min_margin">16dp</dimen>
-
<!-- All Apps -->
<dimen name="all_apps_grid_view_start_margin">0dp</dimen>
<dimen name="all_apps_grid_section_text_size">26sp</dimen>
- <dimen name="all_apps_icon_top_bottom_padding">12dp</dimen>
<dimen name="all_apps_background_canvas_width">850dp</dimen>
<dimen name="all_apps_background_canvas_height">525dp</dimen>
- <dimen name="all_apps_icon_width_gap">36dp</dimen>
<!-- Widget tray -->
<dimen name="widget_section_indent">56dp</dimen>
-
<!-- DragController -->
<dimen name="drag_flingToDeleteMinVelocity">-1000dp</dimen>
</resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index c2d20a3..358d9b6 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -18,7 +18,6 @@
<!-- All Apps -->
<dimen name="all_apps_button_scale_down">8dp</dimen>
<dimen name="all_apps_search_bar_height">54dp</dimen>
- <dimen name="all_apps_icon_top_bottom_padding">14dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">64dp</dimen>
<dimen name="all_apps_empty_search_bg_top_offset">180dp</dimen>
diff --git a/res/values-sw768dp-port/dimens.xml b/res/values-sw768dp-port/dimens.xml
deleted file mode 100644
index 6fb2bf6..0000000
--- a/res/values-sw768dp-port/dimens.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
-<!-- Container -->
- <dimen name="container_max_width">736dp</dimen>
-</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 308c71c..3cfaf02 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -29,6 +29,7 @@
</attr>
<attr name="deferShadowGeneration" format="boolean" />
<attr name="customShadows" format="boolean" />
+ <attr name="centerVertically" format="boolean" />
</declare-styleable>
<!-- PagedView specific attributes. These attributes are used to customize
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 15d4f52..21d9d5c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -37,6 +37,7 @@
<color name="outline_color">#FFFFFFFF</color>
<color name="all_apps_divider_color">#1E000000</color>
<color name="all_apps_caret_color">#FFFFFFFF</color>
+ <color name="all_apps_caret_shadow_color">#22000000</color>
<color name="all_apps_container_color">#FFF2F2F2</color>
<color name="spring_loaded_panel_color">#40FFFFFF</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index a678958..bdedff0 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -86,6 +86,11 @@
<!-- View ID used by cell layout to jail its content -->
<item type="id" name="cell_layout_jail_id" />
+<!-- Deep shortcuts -->
+ <integer name="config_deepShortcutOpenDuration">300</integer>
+ <integer name="config_deepShortcutOpenStagger">20</integer>
+ <integer name="config_deepShortcutHoverDuration">120</integer>
+
<!-- Accessibility actions -->
<item type="id" name="action_remove" />
<item type="id" name="action_uninstall" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 38775f1..54b3d09 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,20 +16,26 @@
<resources>
<!-- Dynamic Grid -->
- <dimen name="dynamic_grid_edge_margin">6dp</dimen>
- <dimen name="dynamic_grid_page_indicator_height">24dp</dimen>
+ <dimen name="dynamic_grid_edge_margin">8dp</dimen>
+ <dimen name="dynamic_grid_page_indicator_height">28dp</dimen>
<dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
<dimen name="dynamic_grid_page_indicator_extra_touch_height">12dp</dimen>
- <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
- <dimen name="dynamic_grid_workspace_page_spacing">8dp</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_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>
<dimen name="dynamic_grid_overview_bar_item_width">80dp</dimen>
- <dimen name="dynamic_grid_overview_bar_spacer_width">20dp</dimen>
-
+ <dimen name="dynamic_grid_overview_bar_spacer_width">25dp</dimen>
+ <dimen name="dynamic_grid_hotseat_height">88dp</dimen>
+ <dimen name="dynamic_grid_hotseat_top_padding">12dp</dimen>
+ <dimen name="dynamic_grid_hotseat_gutter_width">24dp</dimen>
<dimen name="dynamic_grid_workspace_top_padding">12dp</dimen>
+ <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
<!-- Minimum space between workspace and hotseat in spring loaded mode -->
<dimen name="dynamic_grid_min_spring_loaded_space">8dp</dimen>
+ <dimen name="dynamic_grid_container_land_left_padding">118dp</dimen>
+ <dimen name="dynamic_grid_container_land_right_padding">66dp</dimen>
<!-- Drop target bar -->
<dimen name="dynamic_grid_drop_target_size">48dp</dimen>
@@ -54,28 +60,24 @@
<dimen name="container_fastscroll_popup_size">72dp</dimen>
<dimen name="container_fastscroll_popup_text_size">48dp</dimen>
- <item name="container_margin" format="fraction" type="fraction">0%</item>
- <dimen name="container_min_margin">8dp</dimen>
- <dimen name="container_max_width">0dp</dimen>
-
<!-- All Apps -->
<dimen name="all_apps_button_scale_down">0dp</dimen>
<dimen name="all_apps_grid_view_start_margin">0dp</dimen>
<dimen name="all_apps_grid_section_y_offset">8dp</dimen>
<dimen name="all_apps_grid_section_text_size">24sp</dimen>
<dimen name="all_apps_search_bar_height">60dp</dimen>
- <dimen name="all_apps_search_bar_margin_top">5dp</dimen>
+ <dimen name="all_apps_search_bar_margin_top">12dp</dimen>
<dimen name="all_apps_search_bar_icon_margin_right">4dp</dimen>
<dimen name="all_apps_search_bar_icon_margin_top">1dp</dimen>
- <dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
- <dimen name="all_apps_icon_width_gap">24dp</dimen>
<dimen name="all_apps_list_bottom_padding">8dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
<dimen name="all_apps_empty_search_bg_top_offset">144dp</dimen>
<dimen name="all_apps_background_canvas_width">700dp</dimen>
<dimen name="all_apps_background_canvas_height">475dp</dimen>
<dimen name="all_apps_caret_stroke_width">2dp</dimen>
- <dimen name="all_apps_caret_inset">8dp</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>
<!-- Search bar in All Apps -->
<dimen name="all_apps_header_max_elevation">3dp</dimen>
@@ -85,6 +87,7 @@
<dimen name="all_apps_divider_margin_vertical">8dp</dimen>
<dimen name="all_apps_bezel_swipe_height">24dp</dimen>
+
<!-- Widget tray -->
<dimen name="widget_preview_label_vertical_padding">8dp</dimen>
<dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
@@ -152,12 +155,16 @@
<!-- Deep shortcuts -->
<dimen name="deep_shortcuts_elevation">9dp</dimen>
- <dimen name="deep_shortcuts_width">180dp</dimen>
+ <dimen name="bg_pill_width">180dp</dimen>
+ <dimen name="bg_pill_height">48dp</dimen>
+ <dimen name="bg_pill_radius">24dp</dimen>
<dimen name="deep_shortcuts_spacing">4dp</dimen>
<dimen name="deep_shortcuts_drag_view_scale">6dp</dimen>
<!-- an icon with shortcuts must be dragged this much distance away from the nearest edge
of the shortcut container before the container is removed. -->
<dimen name="deep_shortcuts_start_drag_threshold">35dp</dimen>
<dimen name="deep_shortcut_icon_size">36dp</dimen>
+ <dimen name="deep_shortcuts_arrow_horizontal_offset">19dp</dimen>
+ <dimen name="deep_shortcut_anim_translation_y">5dp</dimen>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 3e827a6..532b701 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -78,10 +78,7 @@
</style>
<style name="Icon.DeepShortcut">
- <item name="android:background">@drawable/bg_white_pill</item>
<item name="android:gravity">start|center_vertical</item>
- <item name="android:minWidth">@dimen/deep_shortcuts_width</item>
- <item name="android:maxWidth">@dimen/deep_shortcuts_width</item>
<item name="android:elevation">@dimen/deep_shortcuts_elevation</item>
<item name="android:paddingLeft">7dp</item>
<item name="android:drawablePadding">12dp</item>
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index 57a60a9..96942ee 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
@@ -32,12 +31,16 @@
/**
* A base container view, which supports resizing.
*/
-public abstract class BaseContainerView extends FrameLayout {
+public abstract class BaseContainerView extends FrameLayout
+ implements DeviceProfile.LauncherLayoutChangeListener {
- protected final int mHorizontalPadding;
+ protected int mContainerPaddingLeft;
+ protected int mContainerPaddingRight;
+ protected int mContainerPaddingTop;
+ protected int mContainerPaddingBottom;
- private final InsetDrawable mRevealDrawable;
- private final ColorDrawable mDrawable;
+ private InsetDrawable mRevealDrawable;
+ protected final Drawable mBaseDrawable;
private View mRevealView;
private View mContent;
@@ -53,48 +56,49 @@
public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- Launcher launcher = Launcher.getLauncher(context);
- int width = launcher.getDeviceProfile().availableWidthPx;
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
- this instanceof AllAppsContainerView &&
- !launcher.getDeviceProfile().isVerticalBarLayout()) {
- mHorizontalPadding = 0;
- } else {
- mHorizontalPadding = DeviceProfile.getContainerPadding(context, width);
- }
-
if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
- mDrawable = new ColorDrawable();
- mRevealDrawable = new InsetDrawable(mDrawable,
- mHorizontalPadding, 0, mHorizontalPadding, 0);
+ mBaseDrawable = new ColorDrawable();
} else {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BaseContainerView, defStyleAttr, 0);
- mRevealDrawable = new InsetDrawable(
- a.getDrawable(R.styleable.BaseContainerView_revealBackground),
- mHorizontalPadding, 0, mHorizontalPadding, 0);
- mDrawable = null;
+ mBaseDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground);
a.recycle();
}
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+ grid.addLauncherLayoutChangedListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
+ grid.removeLauncherLayoutChangedListener(this);
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
mContent = findViewById(R.id.main_content);
mRevealView = findViewById(R.id.reveal_view);
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
- mRevealView.setBackground(mRevealDrawable);
- } else {
- mRevealView.setBackground(mRevealDrawable.getConstantState().newDrawable());
- mContent.setBackground(mRevealDrawable);
- }
+ updatePaddings();
+ }
- // We let the content have a intent background, but still have full width.
- // This allows the scroll bar to be used responsive outside the background bounds as well.
- mContent.setPadding(0, 0, 0, 0);
+ @Override
+ public void onLauncherLayoutChanged() {
+ updatePaddings();
+ }
+
+ public void setRevealDrawableColor(int color) {
+ ((ColorDrawable) mBaseDrawable).setColor(color);
}
public final View getContentView() {
@@ -105,7 +109,35 @@
return mRevealView;
}
- public void setRevealDrawableColor(int color) {
- mDrawable.setColor(color);
+ private void updatePaddings() {
+ Context context = getContext();
+ Launcher launcher = Launcher.getLauncher(context);
+
+ if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
+ this instanceof AllAppsContainerView &&
+ !launcher.getDeviceProfile().isVerticalBarLayout()) {
+ mContainerPaddingLeft = mContainerPaddingRight = 0;
+ mContainerPaddingTop = mContainerPaddingBottom = 0;
+ } else {
+ DeviceProfile grid = launcher.getDeviceProfile();
+ int[] padding = grid.getContainerPadding(context);
+ mContainerPaddingLeft = padding[0] + grid.edgeMarginPx;
+ mContainerPaddingRight = padding[1] + grid.edgeMarginPx;
+ if (!launcher.getDeviceProfile().isVerticalBarLayout()) {
+ mContainerPaddingTop = mContainerPaddingBottom = grid.edgeMarginPx;
+ } else {
+ mContainerPaddingTop = mContainerPaddingBottom = 0;
+ }
+ }
+
+ mRevealDrawable = new InsetDrawable(mBaseDrawable,
+ mContainerPaddingLeft, mContainerPaddingTop, mContainerPaddingRight,
+ mContainerPaddingBottom);
+ mRevealView.setBackground(mRevealDrawable);
+ if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
+ // Skip updating the content background
+ } else {
+ mContent.setBackground(mRevealDrawable);
+ }
}
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 33e4e2a..00ec4c2 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -24,6 +24,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -66,6 +67,7 @@
private final Launcher mLauncher;
private Drawable mIcon;
+ private final boolean mCenterVertically;
private final Drawable mBackground;
private OnLongClickListener mOnLongClickListener;
private final CheckLongPressHelper mLongPressHelper;
@@ -119,9 +121,11 @@
if (display == DISPLAY_WORKSPACE) {
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
} else if (display == DISPLAY_ALL_APPS) {
- setTextSize(TypedValue.COMPLEX_UNIT_SP, grid.allAppsIconTextSizeSp);
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
+ setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
defaultIconSize = grid.allAppsIconSizePx;
}
+ mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
defaultIconSize);
@@ -428,6 +432,19 @@
}
@Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mCenterVertically) {
+ Paint.FontMetrics fm = getPaint().getFontMetrics();
+ int cellHeightPx = mIconSize + getCompoundDrawablePadding() +
+ (int) Math.ceil(fm.bottom - fm.top);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(),
+ getPaddingBottom());
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mBackground != null) mBackground.setCallback(null);
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2b130e5..5828dfc 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -29,13 +29,18 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import android.view.ViewGroup.MarginLayoutParams;
import android.widget.FrameLayout;
import com.android.launcher3.config.FeatureFlags;
+import java.util.ArrayList;
+
public class DeviceProfile {
+ public interface LauncherLayoutChangeListener {
+ void onLauncherLayoutChanged();
+ }
+
public final InvariantDeviceProfile inv;
// Device properties
@@ -68,13 +73,18 @@
private int desiredWorkspaceLeftRightMarginPx;
public final int edgeMarginPx;
public final Rect defaultWidgetPadding;
- private final int pageIndicatorHeightPx;
private final int defaultPageSpacingPx;
private final int topWorkspacePadding;
private float dragViewScale;
public float workspaceSpringLoadShrinkFactor;
public final int workspaceSpringLoadedBottomSpace;
+ // Page indicator
+ private final int pageIndicatorHeightPx;
+ private final int pageIndicatorLandGutterLeftNavBarPx;
+ private final int pageIndicatorLandGutterRightNavBarPx;
+ private final int pageIndicatorLandWorkspaceOffsetPx;
+
// Workspace icons
public int iconSizePx;
public int iconTextSizePx;
@@ -96,17 +106,30 @@
public int hotseatCellHeightPx;
public int hotseatIconSizePx;
private int hotseatBarHeightPx;
+ private int hotseatBarTopPaddingPx;
+ private int hotseatLandGutterPx;
// All apps
public int allAppsNumCols;
public int allAppsNumPredictiveCols;
public int allAppsButtonVisualSize;
- public final int allAppsIconSizePx;
- public final float allAppsIconTextSizeSp;
+ public int allAppsIconSizePx;
+ public int allAppsIconDrawablePaddingPx;
+ public float allAppsIconTextSizePx;
+
+ // Containers
+ private final int containerLeftPaddingPx;
+ private final int containerRightPaddingPx;
// Drop Target
public int dropTargetBarSizePx;
+ // Insets
+ private Rect mInsets = new Rect();
+
+ // Listeners
+ private ArrayList<LauncherLayoutChangeListener> mListeners = new ArrayList<>();
+
public DeviceProfile(Context context, InvariantDeviceProfile inv,
Point minSize, Point maxSize,
int width, int height, boolean isLandscape) {
@@ -130,9 +153,15 @@
this.getClass().getName());
defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- desiredWorkspaceLeftRightMarginPx = 2 * edgeMarginPx;
+ 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);
+ 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 =
@@ -152,12 +181,14 @@
dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size);
workspaceSpringLoadedBottomSpace =
res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space);
-
- // AllApps uses the original non-scaled icon text size
- allAppsIconTextSizeSp = inv.iconTextSize;
-
- // AllApps uses the original non-scaled icon size
- allAppsIconSizePx = Utilities.pxFromDp(inv.iconSize, dm);
+ hotseatBarHeightPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height);
+ hotseatBarTopPaddingPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
+ hotseatLandGutterPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_gutter_width);
+ containerLeftPaddingPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_container_land_left_padding);
+ containerRightPaddingPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_container_land_right_padding);
// Determine sizes.
widthPx = width;
@@ -175,6 +206,18 @@
computeAllAppsButtonSize(context);
}
+ public void addLauncherLayoutChangedListener(LauncherLayoutChangeListener listener) {
+ if (!mListeners.contains(listener)) {
+ mListeners.add(listener);
+ }
+ }
+
+ public void removeLauncherLayoutChangedListener(LauncherLayoutChangeListener listener) {
+ if (mListeners.contains(listener)) {
+ mListeners.remove(listener);
+ }
+ }
+
/**
* Determine the exact visual footprint of the all apps button, taking into account scaling
* and internal padding of the drawable.
@@ -208,6 +251,9 @@
iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale);
iconDrawablePaddingPx = drawablePadding;
hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale);
+ allAppsIconSizePx = iconSizePx;
+ allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
+ allAppsIconTextSizePx = iconTextSizePx;
// Calculate the actual text height
Paint textPaint = new Paint();
@@ -220,7 +266,6 @@
dragViewScale = (iconSizePx + scaleDps) / iconSizePx;
// Hotseat
- hotseatBarHeightPx = iconSizePx + 4 * edgeMarginPx;
hotseatCellWidthPx = iconSizePx;
hotseatCellHeightPx = iconSizePx;
@@ -247,20 +292,15 @@
folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
}
+ public void updateInsets(Rect insets) {
+ mInsets.set(insets);
+ }
+
/**
* @param recyclerViewWidth the available width of the AllAppsRecyclerView
*/
- public void updateAppsViewNumCols(Resources res, int recyclerViewWidth) {
- int appsViewLeftMarginPx =
- res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
- int allAppsCellWidthGap =
- res.getDimensionPixelSize(R.dimen.all_apps_icon_width_gap);
- int availableAppsWidthPx = (recyclerViewWidth > 0) ? recyclerViewWidth : availableWidthPx;
- int numAppsCols = (availableAppsWidthPx + allAppsCellWidthGap - appsViewLeftMarginPx) /
- (allAppsIconSizePx + allAppsCellWidthGap);
- int numPredictiveAppCols = Math.max(inv.minAllAppsPredictionColumns, numAppsCols);
- allAppsNumCols = numAppsCols;
- allAppsNumPredictiveCols = numPredictiveAppCols;
+ public void updateAppsViewNumCols() {
+ allAppsNumCols = allAppsNumPredictiveCols = inv.numColumns;
}
/** Returns the width and height of the search bar, ignoring any padding. */
@@ -309,9 +349,13 @@
public Rect getWorkspacePadding(Rect recycle) {
Rect padding = recycle == null ? new Rect() : recycle;
if (isVerticalBarLayout()) {
- // in case of isVerticalBarLayout, the hotseat is always on the right and the drop
- // target bar is on the left, independent of the layout direction.
- padding.set(dropTargetBarSizePx, edgeMarginPx, hotseatBarHeightPx, edgeMarginPx);
+ if (mInsets.left > 0) {
+ padding.set(mInsets.left + pageIndicatorLandGutterLeftNavBarPx, 0,
+ hotseatBarHeightPx + hotseatLandGutterPx - mInsets.left, 2 * edgeMarginPx);
+ } else {
+ padding.set(pageIndicatorLandGutterRightNavBarPx, 0,
+ hotseatBarHeightPx + hotseatLandGutterPx, 2 * edgeMarginPx);
+ }
} else {
int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
if (isTablet) {
@@ -331,10 +375,10 @@
availablePaddingX / 2, paddingBottom + availablePaddingY / 2);
} else {
// Pad the top and bottom of the workspace with search/hotseat bar sizes
- padding.set(desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.left,
+ padding.set(desiredWorkspaceLeftRightMarginPx,
topWorkspacePadding,
- desiredWorkspaceLeftRightMarginPx - defaultWidgetPadding.right,
- paddingBottom);
+ desiredWorkspaceLeftRightMarginPx,
+ hotseatBarHeightPx + pageIndicatorHeightPx);
}
}
return padding;
@@ -348,7 +392,7 @@
// In portrait, we want the pages spaced such that there is no
// overhang of the previous / next page into the current page viewport.
// We assume symmetrical padding in portrait mode.
- return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding(null).left);
+ return Math.max(defaultPageSpacingPx, getWorkspacePadding(null).left + 1);
}
}
@@ -389,7 +433,7 @@
return visibleChildren;
}
- public void layout(Launcher launcher) {
+ public void layout(Launcher launcher, boolean notifyListeners) {
FrameLayout.LayoutParams lp;
boolean hasVerticalBarLayout = isVerticalBarLayout();
final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());
@@ -400,18 +444,19 @@
lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
lp.width = searchBarBounds.x;
lp.height = searchBarBounds.y;
- lp.topMargin = edgeMarginPx;
+ lp.topMargin = mInsets.top + edgeMarginPx;
searchBar.setLayoutParams(lp);
// Layout the workspace
PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
- Rect padding = getWorkspacePadding(null);
- workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+ Rect workspacePadding = getWorkspacePadding(null);
+ workspace.setPadding(workspacePadding.left, workspacePadding.top, workspacePadding.right,
+ workspacePadding.bottom);
workspace.setPageSpacing(getWorkspacePageSpacing());
View qsbContainer = launcher.getQsbContainer();
lp = (FrameLayout.LayoutParams) qsbContainer.getLayoutParams();
- lp.topMargin = padding.top;
+ lp.topMargin = mInsets.top + workspacePadding.top;
qsbContainer.setLayoutParams(lp);
// Layout the hotseat
@@ -428,26 +473,29 @@
// Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
// screen regardless of RTL
lp.gravity = Gravity.RIGHT;
- lp.width = hotseatBarHeightPx;
+ lp.width = hotseatBarHeightPx + mInsets.left + mInsets.right;
lp.height = LayoutParams.MATCH_PARENT;
hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
+ hotseat.setPadding(mInsets.left, 0, mInsets.right, 0);
} else if (isTablet) {
// Pad the hotseat with the workspace padding calculated above
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
- lp.height = hotseatBarHeightPx;
+ lp.height = hotseatBarHeightPx + mInsets.bottom;
hotseat.findViewById(R.id.layout).setPadding(
- hotseatAdjustment + padding.left, 0,
- hotseatAdjustment + padding.right, 2 * edgeMarginPx);
+ hotseatAdjustment + workspacePadding.left, 0,
+ hotseatAdjustment + workspacePadding.right, 2 * edgeMarginPx);
+ hotseat.setPadding(0, hotseatBarTopPaddingPx, 0, mInsets.bottom);
} else {
// For phones, layout the hotseat without any bottom margin
// to ensure that we have space for the folders
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
- lp.height = hotseatBarHeightPx;
+ lp.height = hotseatBarHeightPx + mInsets.bottom;
hotseat.findViewById(R.id.layout).setPadding(
- hotseatAdjustment + padding.left, 0,
- hotseatAdjustment + padding.right, 0);
+ hotseatAdjustment + workspacePadding.left, 0,
+ hotseatAdjustment + workspacePadding.right, 0);
+ hotseat.setPadding(0, hotseatBarTopPaddingPx, 0, mInsets.bottom);
}
hotseat.setLayoutParams(lp);
@@ -455,11 +503,21 @@
View pageIndicator = launcher.findViewById(R.id.page_indicator);
if (pageIndicator != null) {
lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams();
- if (!hasVerticalBarLayout) {
+ 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.bottomMargin = workspacePadding.bottom;
+ } else {
// Put the page indicators above the hotseat
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
lp.width = LayoutParams.WRAP_CONTENT;
- lp.bottomMargin = hotseatBarHeightPx;
+ lp.height = pageIndicatorHeightPx;
+ lp.bottomMargin = hotseatBarHeightPx + mInsets.bottom;
}
pageIndicator.setLayoutParams(lp);
}
@@ -468,7 +526,7 @@
ViewGroup overviewMode = launcher.getOverviewPanel();
if (overviewMode != null) {
lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();
- lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
int visibleChildCount = getVisibleChildCount(overviewMode);
int totalItemWidth = visibleChildCount * overviewModeBarItemWidthPx;
@@ -476,30 +534,15 @@
lp.width = Math.min(availableWidthPx, maxWidth);
lp.height = getOverviewModeButtonBarHeight();
+ // Center the overview buttons on the workspace page
+ lp.leftMargin = workspacePadding.left + (availableWidthPx -
+ workspacePadding.left - workspacePadding.right - lp.width) / 2;
overviewMode.setLayoutParams(lp);
+ }
- if (lp.width > totalItemWidth && visibleChildCount > 1) {
- // We have enough space. Lets add some margin too.
- int margin = (lp.width - totalItemWidth) / (visibleChildCount-1);
- View lastChild = null;
-
- // Set margin of all visible children except the last visible child
- for (int i = 0; i < visibleChildCount; i++) {
- if (lastChild != null) {
- MarginLayoutParams clp = (MarginLayoutParams) lastChild.getLayoutParams();
- if (isLayoutRtl) {
- clp.leftMargin = margin;
- } else {
- clp.rightMargin = margin;
- }
- lastChild.setLayoutParams(clp);
- lastChild = null;
- }
- View thisChild = overviewMode.getChildAt(i);
- if (thisChild.getVisibility() != View.GONE) {
- lastChild = thisChild;
- }
- }
+ if (notifyListeners) {
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onLauncherLayoutChanged();
}
}
}
@@ -517,17 +560,20 @@
}
- public static final int getContainerPadding(Context context, int availableWidth) {
+ /**
+ * @return the left/right paddings for all containers.
+ */
+ public final int[] getContainerPadding(Context context) {
Resources res = context.getResources();
- int maxSize = res.getDimensionPixelSize(R.dimen.container_max_width);
- int minMargin = res.getDimensionPixelSize(R.dimen.container_min_margin);
-
- if (maxSize > 0) {
- return Math.max(minMargin, (availableWidth - maxSize) / 2);
- } else {
- return Math.max(minMargin,
- (int) res.getFraction(R.fraction.container_margin, availableWidth, 1));
+ // No paddings for portrait phone
+ if (isPhone && !isVerticalBarLayout()) {
+ return new int[] {0, 0};
}
+
+ // In landscape, we just match the vertical display width
+ int containerWidth = heightPx;
+ int padding = (availableWidthPx - containerWidth) / 2;
+ return new int[]{ padding, padding };
}
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 7e2b42e..084de70 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -39,7 +39,7 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
public class Hotseat extends FrameLayout
- implements UserEventDispatcher.LaunchSourceProvider, Insettable {
+ implements UserEventDispatcher.LaunchSourceProvider {
private CellLayout mContent;
@@ -49,9 +49,6 @@
private final boolean mHasVerticalHotseat;
@ViewDebug.ExportedProperty(category = "launcher")
- private Rect mInsets = new Rect();
-
- @ViewDebug.ExportedProperty(category = "launcher")
private int mBackgroundColor;
@ViewDebug.ExportedProperty(category = "launcher")
private ColorDrawable mBackground;
@@ -180,28 +177,6 @@
targetParent.containerType = LauncherLogProto.HOTSEAT;
}
- //Overridden so that the background color extends behind the navigation buttons.
- @Override
- public void setInsets(Rect insets) {
- int rightInset = insets.right - mInsets.right;
- int bottomInset = insets.bottom - mInsets.bottom;
- mInsets.set(insets);
- LayoutParams lp = (LayoutParams) getLayoutParams();
- if (mHasVerticalHotseat) {
- setPadding(getPaddingLeft(), getPaddingTop(),
- getPaddingRight() + rightInset, getPaddingBottom());
- if (lp.width != LayoutParams.MATCH_PARENT && lp.width != LayoutParams.WRAP_CONTENT) {
- lp.width += rightInset;
- }
- } else {
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
- getPaddingBottom() + bottomInset);
- if (lp.height != LayoutParams.MATCH_PARENT && lp.height != LayoutParams.WRAP_CONTENT) {
- lp.height += bottomInset;
- }
- }
- }
-
public void updateColor(ExtractedColors extractedColors, boolean animate) {
if (!mHasVerticalHotseat) {
int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX, Color.TRANSPARENT);
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 9ce941b..a49162c 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -72,6 +72,7 @@
private static final String EMPTY_CLASS_NAME = ".";
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_IGNORE_CACHE = false;
private static final int LOW_RES_SCALE_FACTOR = 5;
@@ -552,7 +553,7 @@
mCache.put(cacheKey, entry);
// Check the DB first.
- if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) {
+ if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
if (info != null) {
entry.icon = Utilities.createBadgedIconBitmap(
mIconProvider.getIcon(info, mIconDpi), info.getUser(),
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 4e6911c..38545e2 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -67,6 +67,7 @@
/**
* The minimum number of predicted apps in all apps.
*/
+ @Deprecated
int minAllAppsPredictionColumns;
/**
@@ -103,11 +104,6 @@
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) {
- // Ensure that we have an odd number of hotseat items (since we need to place all apps)
- if (hs % 2 == 0) {
- throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
- }
-
name = n;
minWidthDps = w;
minHeightDps = h;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b7f033e..73cd800 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -438,7 +438,7 @@
setContentView(R.layout.launcher);
setupViews();
- mDeviceProfile.layout(this);
+ mDeviceProfile.layout(this, false /* notifyListeners */);
mExtractedColors = new ExtractedColors();
loadExtractedColorsAndColorItems();
@@ -521,6 +521,11 @@
}
}
+ public void onInsetsChanged(Rect insets) {
+ mDeviceProfile.updateInsets(insets);
+ mDeviceProfile.layout(this, true /* notifyListeners */);
+ }
+
/**
* Call this after onCreate to set or clear overlay.
*/
@@ -2009,9 +2014,9 @@
}
@Override
- public void startActivityForResult(Intent intent, int requestCode) {
+ public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
onStartForResult(requestCode);
- super.startActivityForResult(intent, requestCode);
+ super.startActivityForResult(intent, requestCode, options);
}
@Override
@@ -2725,10 +2730,12 @@
int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen());
float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
- startActivityForResult(new Intent(Intent.ACTION_SET_WALLPAPER)
+
+ Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
.setPackage(pickerPackage)
- .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset),
- REQUEST_PICK_WALLPAPER);
+ .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset);
+ intent.setSourceBounds(getViewBounds(v));
+ startActivityForResult(intent, REQUEST_PICK_WALLPAPER, getActivityLaunchOptions(v));
}
/**
@@ -2876,6 +2883,12 @@
return null;
}
+ private Rect getViewBounds(View v) {
+ int[] pos = new int[2];
+ v.getLocationOnScreen(pos);
+ return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
+ }
+
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
@@ -2896,10 +2909,7 @@
// Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- intent.setSourceBounds(
- new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight()));
+ intent.setSourceBounds(getViewBounds(v));
}
try {
if (Utilities.ATLEAST_MARSHMALLOW && item != null
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index a75edb7..ddd60c8 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2782,7 +2782,7 @@
for (UserHandleCompat user : mUserManager.getUserProfiles()) {
List<ShortcutInfoCompat> shortcuts = mDeepShortcutManager
.queryForAllShortcuts(user);
- updateDeepShortcutMap(null, shortcuts);
+ updateDeepShortcutMap(null, user, shortcuts);
}
synchronized (LoaderTask.this) {
if (mStopped) {
@@ -2804,13 +2804,17 @@
}
}
- // Clear all the shortcuts for the given package, and re-add the new shortcuts.
- private void updateDeepShortcutMap(String packageName, List<ShortcutInfoCompat> shortcuts) {
- // Remove all keys associated with the given package.
+ /**
+ * Clear all the shortcuts for the given package, and re-add the new shortcuts.
+ */
+ private void updateDeepShortcutMap(
+ String packageName, UserHandleCompat user, List<ShortcutInfoCompat> shortcuts) {
if (packageName != null) {
Iterator<ComponentKey> keysIter = mBgDeepShortcutMap.keySet().iterator();
while (keysIter.hasNext()) {
- if (keysIter.next().componentName.getPackageName().equals(packageName)) {
+ ComponentKey next = keysIter.next();
+ if (next.componentName.getPackageName().equals(packageName)
+ && next.user.equals(user)) {
keysIter.remove();
}
}
@@ -3336,7 +3340,7 @@
bindUpdatedShortcuts(updatedShortcutInfos, mUser);
// Update the deep shortcut map, in case the list of ids has changed for an activity.
- updateDeepShortcutMap(mPackageName, mShortcuts);
+ updateDeepShortcutMap(mPackageName, mUser, mShortcuts);
bindDeepShortcuts();
}
}
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 7bcf5d0..643d48a 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -44,6 +44,7 @@
@TargetApi(23)
@Override
protected boolean fitSystemWindows(Rect insets) {
+ boolean rawInsetsChanged = !mInsets.equals(insets);
mDrawSideInsetBar = (insets.right > 0 || insets.left > 0) &&
(!Utilities.ATLEAST_MARSHMALLOW ||
getContext().getSystemService(ActivityManager.class).isLowRamDevice());
@@ -61,6 +62,12 @@
}
}
+ if (rawInsetsChanged) {
+ // Update the grid again
+ Launcher launcher = Launcher.getLauncher(getContext());
+ launcher.onInsetsChanged(insets);
+ }
+
return true; // I'll take it from here
}
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index c3b7fe7..5c7e670 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -35,8 +35,8 @@
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.CircleRevealOutlineProvider;
import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.UiThreadCircularReveal;
import com.android.launcher3.widget.WidgetsContainerView;
import java.util.HashMap;
@@ -345,8 +345,8 @@
float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
revealView, buttonView);
- Animator reveal = UiThreadCircularReveal.createCircularReveal(revealView, width / 2,
- height / 2, startRadius, revealRadius);
+ Animator reveal = new CircleRevealOutlineProvider(width / 2, height / 2,
+ startRadius, revealRadius).createRevealAnimator(revealView);
reveal.setDuration(revealDuration);
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
if (listener != null) {
@@ -789,8 +789,8 @@
float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
AnimatorListenerAdapter listener =
pCb.getMaterialRevealViewAnimatorListener(revealView, buttonView);
- Animator reveal = UiThreadCircularReveal.createCircularReveal(revealView, width / 2,
- height / 2, revealRadius, finalRadius);
+ Animator reveal = new CircleRevealOutlineProvider(width / 2, height / 2,
+ revealRadius, finalRadius).createRevealAnimator(revealView);
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
reveal.setDuration(revealDuration);
reveal.setStartDelay(itemsAlphaStagger);
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index c016aa9..d98734b 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -129,7 +129,7 @@
if (child instanceof LauncherAppWidgetHostView) {
// Widgets have their own padding, so skip
} else {
- // Otherwise, center the icon
+ // Otherwise, center the icon/folder
int cHeight = getCellContentHeight();
int cellPaddingY = (int) Math.max(0, ((lp.height - cHeight) / 2f));
int cellPaddingX = (int) (grid.edgeMarginPx / 2f);
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index b8f0ec9..a9f73c2 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -307,7 +307,7 @@
.getShortcutIconDrawable(shortcutInfo,
launcherAppState.getInvariantDeviceProfile().fillResIconDpi);
Bitmap icon = unbadgedIcon == null ? null
- : Utilities.createBadgedIconBitmap(unbadgedIcon, user, context);
+ : Utilities.createBadgedIconBitmapWithShadow(unbadgedIcon, user, context);
setIcon(icon != null ? icon : launcherAppState.getIconCache().getDefaultIcon(user));
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index cedbe74..7b1a16c 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -40,6 +40,7 @@
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
@@ -64,6 +65,7 @@
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.graphics.ShadowGenerator;
import com.android.launcher3.util.IconNormalizer;
import java.io.ByteArrayOutputStream;
@@ -244,7 +246,7 @@
public static Bitmap createBadgedIconBitmap(
Drawable icon, UserHandleCompat user, Context context) {
float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
- 1 : IconNormalizer.getInstance().getScale(icon);
+ 1 : IconNormalizer.getInstance().getScale(icon, null);
Bitmap bitmap = createIconBitmap(icon, context, scale);
if (Utilities.ATLEAST_LOLLIPOP && user != null
&& !UserHandleCompat.myUserHandle().equals(user)) {
@@ -262,6 +264,34 @@
}
/**
+ * Same as {@link #createBadgedIconBitmap} but adds a shadow before badging the icon
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public static Bitmap createBadgedIconBitmapWithShadow(
+ Drawable icon, UserHandleCompat user, Context context) {
+ RectF iconBounds = new RectF();
+ float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
+ 1 : IconNormalizer.getInstance().getScale(icon, iconBounds);
+ scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
+
+ Bitmap bitmap = createIconBitmap(icon, context, scale);
+ bitmap = ShadowGenerator.getInstance().recreateIcon(bitmap);
+ if (Utilities.ATLEAST_LOLLIPOP && user != null
+ && !UserHandleCompat.myUserHandle().equals(user)) {
+ BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
+ Drawable badged = context.getPackageManager().getUserBadgedIcon(
+ drawable, user.getUser());
+ if (badged instanceof BitmapDrawable) {
+ return ((BitmapDrawable) badged).getBitmap();
+ } else {
+ return createIconBitmap(badged, context);
+ }
+ } else {
+ return bitmap;
+ }
+ }
+
+ /**
* Returns a bitmap suitable for the all apps view.
*/
public static Bitmap createIconBitmap(Drawable icon, Context context) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 344c389..75d4a8d 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -53,11 +53,9 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import android.widget.Space;
import android.widget.TextView;
import com.android.launcher3.Launcher.CustomContentCallbacks;
@@ -315,6 +313,7 @@
// Total over scrollX in the overlay direction.
private float mOverlayTranslation;
private int mFirstPageScrollX;
+ private boolean mIgnoreQsbScroll;
// Handles workspace state transitions
private WorkspaceStateTransitionAnimation mStateTransitionAnimation;
@@ -366,16 +365,7 @@
@Override
public void setInsets(Rect insets) {
- int extraLeftPadding = insets.left - mInsets.left;
mInsets.set(insets);
- if (extraLeftPadding != 0) {
- /**
- * Initial layout assumes that the insets is on the right,
- * {@link DeviceProfile#getWorkspacePadding()}. Compensate for the difference.
- */
- setPadding(getPaddingLeft() + extraLeftPadding, getPaddingTop(),
- getPaddingRight() - extraLeftPadding, getPaddingBottom());
- }
CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);
if (customScreen != null) {
@@ -1395,8 +1385,10 @@
}
private void onWorkspaceOverallScrollChanged() {
- mLauncher.getQsbContainer().setTranslationX(
- mOverlayTranslation + mFirstPageScrollX - getScrollX());
+ if (!mIgnoreQsbScroll) {
+ mLauncher.getQsbContainer().setTranslationX(
+ mOverlayTranslation + mFirstPageScrollX - getScrollX());
+ }
}
@Override
@@ -1517,21 +1509,26 @@
/**
* Moves the Hotseat UI in the provided direction.
* @param direction the direction to move the workspace
- * @param translation the amound of shift.
+ * @param translation the amount of shift.
* @param alpha the alpha for the hotseat page
*/
public void setHotseatTranslationAndAlpha(Direction direction, float translation, float alpha) {
Property<View, Float> property = direction.viewProperty;
- property.set(mPageIndicator, translation);
+ // Skip the page indicator movement in the vertical bar layout
+ if (direction != Direction.Y || !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ property.set(mPageIndicator, translation);
+ }
property.set(mLauncher.getHotseat(), translation);
setHotseatAlphaAtIndex(alpha, direction.ordinal());
}
private void setHotseatAlphaAtIndex(float alpha, int index) {
mHotseatAlpha[index] = alpha;
- float finalAlpha = mHotseatAlpha[0] * mHotseatAlpha[1] * mHotseatAlpha[2];
+ final float hotseatAlpha = mHotseatAlpha[0] * mHotseatAlpha[1] * mHotseatAlpha[2];
+ final float pageIndicatorAlpha = mHotseatAlpha[0] * mHotseatAlpha[2];
- mLauncher.getHotseat().setAlpha(finalAlpha);
+ mLauncher.getHotseat().setAlpha(hotseatAlpha);
+ mPageIndicator.setAlpha(pageIndicatorAlpha);
}
public ValueAnimator createHotseatAlphaAnimator(float finalValue) {
@@ -1803,6 +1800,33 @@
super.onLayout(changed, left, top, right, bottom);
mFirstPageScrollX = getScrollForPage(0);
onWorkspaceOverallScrollChanged();
+
+ final LayoutTransition transition = getLayoutTransition();
+ // If the transition is running defer updating max scroll, as some empty pages could
+ // still be present, and a max scroll change could cause sudden jumps in scroll.
+ if (transition != null && transition.isRunning()) {
+ transition.addTransitionListener(new LayoutTransition.TransitionListener() {
+
+ @Override
+ public void startTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {
+ mIgnoreQsbScroll = true;
+ }
+
+ @Override
+ public void endTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {
+ // Wait until all transitions are complete.
+ if (!transition.isRunning()) {
+ mIgnoreQsbScroll = false;
+ transition.removeTransitionListener(this);
+ mFirstPageScrollX = getScrollForPage(0);
+ onWorkspaceOverallScrollChanged();
+ }
+ }
+ });
+ }
+
}
@Override
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 195ab47..3ef510c 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.allapps;
-import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
@@ -31,7 +30,6 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
import com.android.launcher3.AppInfo;
import com.android.launcher3.BaseContainerView;
@@ -242,6 +240,7 @@
}
mSearchBarController = searchController;
mSearchBarController.initialize(mApps, mSearchInput, mLauncher, this);
+ mSearchBarController.setHintView(findViewById(R.id.search_hint));
mAdapter.setSearchController(mSearchBarController);
}
@@ -312,36 +311,6 @@
mSearchContainerOffsetTop = getResources().getDimensionPixelSize(
R.dimen.all_apps_search_bar_margin_top);
- final View searchHint = findViewById(R.id.search_hint);
- final ObjectAnimator searchInputAnimator = ObjectAnimator.ofFloat(mSearchInput,
- View.TRANSLATION_X, 0);
- searchInputAnimator.setDuration(getContext().getResources().getInteger(
- R.integer.config_searchHintAnimationDuration));
- searchInputAnimator.setInterpolator(AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.accelerate_decelerate));
-
- mSearchInput.setOnFocusChangeListener(new OnFocusChangeListener() {
- @Override
- public void onFocusChange(View view, boolean focused) {
- if (focused) {
- searchHint.setVisibility(View.INVISIBLE);
- if (searchInputAnimator.isRunning()) {
- searchInputAnimator.end();
- }
-
- if (Utilities.isRtl(getContext().getResources())) {
- searchInputAnimator.setFloatValues(-searchHint.getLeft(), 0);
- } else {
- searchInputAnimator.setFloatValues(searchHint.getLeft(), 0);
- }
- searchInputAnimator.start();
- } else {
- searchHint.setVisibility(View.VISIBLE);
- mSearchInput.setTranslationX(0);
- }
- }
- });
-
mElevationController = Utilities.ATLEAST_LOLLIPOP
? new HeaderElevationController.ControllerVL(mSearchContainer)
: new HeaderElevationController.ControllerV16(mSearchContainer);
@@ -378,12 +347,10 @@
int widthPx = MeasureSpec.getSize(widthMeasureSpec);
int heightPx = MeasureSpec.getSize(heightMeasureSpec);
updatePaddingsAndMargins(widthPx, heightPx);
- mContentBounds.set(mHorizontalPadding, 0, widthPx - mHorizontalPadding, heightPx);
+ mContentBounds.set(mContainerPaddingLeft, 0, widthPx - mContainerPaddingRight, heightPx);
DeviceProfile grid = mLauncher.getDeviceProfile();
- int availableWidth = (!mContentBounds.isEmpty() ? mContentBounds.width() : widthPx)
- - 2 * mAppsRecyclerView.getMaxScrollbarWidth();
- grid.updateAppsViewNumCols(getResources(), availableWidth);
+ grid.updateAppsViewNumCols();
if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
if (mNumAppsPerRow != grid.inv.numColumns ||
mNumPredictedAppsPerRow != grid.inv.numColumns) {
@@ -399,9 +366,9 @@
getResources().getDimensionPixelSize(
R.dimen.container_fastscroll_thumb_max_width);
mSearchContainer.setPadding(
- rvPadding - mHorizontalPadding + thumbMaxWidth,
+ rvPadding - mContainerPaddingLeft + thumbMaxWidth,
mSearchContainer.getPaddingTop(),
- rvPadding - mHorizontalPadding + thumbMaxWidth,
+ rvPadding - mContainerPaddingRight + thumbMaxWidth,
mSearchContainer.getPaddingBottom());
}
}
@@ -414,7 +381,7 @@
// Update the number of items in the grid before we measure the view
// TODO: mSectionNamesMargin is currently 0, but also account for it,
// if it's enabled in the future.
- grid.updateAppsViewNumCols(getResources(), availableWidth);
+ grid.updateAppsViewNumCols();
if (mNumAppsPerRow != grid.allAppsNumCols ||
mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) {
mNumAppsPerRow = grid.allAppsNumCols;
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 39fe0f8..d8f9fb1 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -20,6 +20,7 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
@@ -37,6 +38,8 @@
import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -331,7 +334,9 @@
private final boolean mIsRtl;
// Section drawing
+ @Deprecated
private final int mSectionNamesMargin;
+ @Deprecated
private final int mSectionHeaderOffset;
private final Paint mSectionTextPaint;
@@ -452,6 +457,14 @@
icon.setLongPressTimeout(ViewConfiguration.get(parent.getContext())
.getLongPressTimeout());
icon.setOnFocusChangeListener(mIconFocusListener);
+
+ // Ensure the all apps icon height matches the workspace icons
+ DeviceProfile profile = mLauncher.getDeviceProfile();
+ Point cellSize = profile.getCellSize();
+ GridLayoutManager.LayoutParams lp =
+ (GridLayoutManager.LayoutParams) icon.getLayoutParams();
+ lp.height = cellSize.y;
+ icon.setLayoutParams(lp);
return new ViewHolder(icon);
}
case VIEW_TYPE_EMPTY_SEARCH:
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 93da297..641656c 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -120,10 +120,9 @@
// Icons
BubbleTextView icon = (BubbleTextView) adapter.onCreateViewHolder(this,
AllAppsGridAdapter.VIEW_TYPE_ICON).mContent;
- icon.applyDummyInfo();
- icon.measure(widthMeasureSpec, heightMeasureSpec);
- mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, icon.getMeasuredHeight());
- mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, icon.getMeasuredHeight());
+ int iconHeight = icon.getLayoutParams().height;
+ mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_ICON, iconHeight);
+ mViewHeights.put(AllAppsGridAdapter.VIEW_TYPE_PREDICTION_ICON, iconHeight);
// Search divider
View searchDivider = adapter.onCreateViewHolder(this,
diff --git a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
index ac35932..b4a71ca 100644
--- a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
@@ -39,7 +39,8 @@
* An interface to a search box that AllApps can command.
*/
public abstract class AllAppsSearchBarController
- implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener {
+ implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
+ View.OnFocusChangeListener {
protected Launcher mLauncher;
protected AlphabeticalAppsList mApps;
@@ -49,6 +50,8 @@
protected DefaultAppSearchAlgorithm mSearchAlgorithm;
protected InputMethodManager mInputMethodManager;
+ protected View mHintView;
+
public void setVisibility(int visibility) {
mInput.setVisibility(visibility);
}
@@ -66,6 +69,7 @@
mInput.addTextChangedListener(this);
mInput.setOnEditorActionListener(this);
mInput.setOnBackKeyListener(this);
+ mInput.setOnFocusChangeListener(this);
mInputMethodManager = (InputMethodManager)
mInput.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -126,6 +130,27 @@
return false;
}
+ @Override
+ public void onFocusChange(View view, boolean focused) {
+ if (mHintView != null) {
+ mHintView.setVisibility(focused ? View.INVISIBLE : View.VISIBLE);
+ }
+ }
+
+ /**
+ * Sets a view to serve as the search field's hint.
+ */
+ public void setHintView(View hintView) {
+ mHintView = hintView;
+ }
+
+ /**
+ * Returns the search field's hint view.
+ */
+ public View getHintView() {
+ return mHintView;
+ }
+
/**
* Resets the search bar state.
*/
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 85af60e..03b3107 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -5,7 +5,6 @@
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
-import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -299,6 +298,7 @@
mShiftCurrent = progress;
float alpha = calcAlphaAllApps(progress);
float workspaceHotseatAlpha = 1 - alpha;
+ float interpolation = mAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
int color = (Integer) mEvaluator.evaluate(mDecelInterpolator.getInterpolation(alpha),
mHotseatBackgroundColor, mAllAppsBackgroundColor);
@@ -307,14 +307,13 @@
mAppsView.setTranslationY(progress);
mWorkspace.setWorkspaceYTranslationAndAlpha(
PARALLAX_COEFFICIENT * (-mShiftRange + progress),
- mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
- if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- mWorkspace.setHotseatTranslationAndAlpha(Direction.Y, -mShiftRange + progress,
- mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+ interpolation);
+ if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ mWorkspace.setHotseatTranslationAndAlpha(Direction.Y,
+ PARALLAX_COEFFICIENT * (-mShiftRange + progress), interpolation);
} else {
mWorkspace.setHotseatTranslationAndAlpha(Direction.Y,
- PARALLAX_COEFFICIENT * (-mShiftRange + progress),
- mAccelInterpolator.getInterpolation(workspaceHotseatAlpha));
+ -mShiftRange + progress, interpolation);
}
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index b70c165..7127ec4 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -440,7 +440,7 @@
mPredictedApps.add(info);
} else {
if (ProviderConfig.IS_DOGFOOD_BUILD) {
- Log.e(TAG, "Predicted app not found: " + ck.flattenToString(mLauncher));
+ Log.e(TAG, "Predicted app not found: " + ck);
}
}
// Stop at the number of predicted apps
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 556be0c..2fbbad5 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -80,8 +80,8 @@
import com.android.launcher3.pageindicators.PageIndicatorDots;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.CircleRevealOutlineProvider;
import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.UiThreadCircularReveal;
import java.util.ArrayList;
import java.util.Collections;
@@ -554,8 +554,8 @@
int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
float radius = (float) Math.hypot(rx, ry);
- Animator reveal = UiThreadCircularReveal.createCircularReveal(this, (int) getPivotX(),
- (int) getPivotY(), 0, radius);
+ Animator reveal = new CircleRevealOutlineProvider((int) getPivotX(),
+ (int) getPivotY(), 0, radius).createRevealAnimator(this);
reveal.setDuration(mMaterialExpandDuration);
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
new file mode 100644
index 0000000..2b24ec9
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BlurMaskFilter;
+import android.graphics.BlurMaskFilter.Blur;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.Preconditions;
+
+/**
+ * Utility class to add shadows to bitmaps.
+ */
+public class ShadowGenerator {
+
+ // Percent of actual icon size
+ private static final float HALF_DISTANCE = 0.5f;
+ private static final float BLUR_FACTOR = 0.5f/48;
+
+ // Percent of actual icon size
+ private static final float KEY_SHADOW_DISTANCE = 1f/48;
+ private static final int KEY_SHADOW_ALPHA = 61;
+
+ private static final int AMBIENT_SHADOW_ALPHA = 30;
+
+ private static final Object LOCK = new Object();
+ // Singleton object guarded by {@link #LOCK}
+ private static ShadowGenerator sShadowGenerator;
+
+ private final int mIconSize;
+
+ private final Canvas mCanvas;
+ private final Paint mBlurPaint;
+ private final Paint mDrawPaint;
+
+ private ShadowGenerator() {
+ mIconSize = LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
+ mCanvas = new Canvas();
+ mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ mBlurPaint.setMaskFilter(new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL));
+ mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+ }
+
+ public synchronized Bitmap recreateIcon(Bitmap icon) {
+ int[] offset = new int[2];
+ Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
+ Bitmap result = Bitmap.createBitmap(mIconSize, mIconSize, Config.ARGB_8888);
+ mCanvas.setBitmap(result);
+
+ // Draw ambient shadow
+ mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
+ mCanvas.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
+
+ // Draw key shadow
+ mDrawPaint.setAlpha(KEY_SHADOW_ALPHA);
+ mCanvas.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint);
+
+ // Draw the icon
+ mDrawPaint.setAlpha(255);
+ mCanvas.drawBitmap(icon, 0, 0, mDrawPaint);
+
+ mCanvas.setBitmap(null);
+ return result;
+ }
+
+ public static ShadowGenerator getInstance() {
+ Preconditions.assertNonUiThread();
+ synchronized (LOCK) {
+ if (sShadowGenerator == null) {
+ sShadowGenerator = new ShadowGenerator();
+ }
+ }
+ return sShadowGenerator;
+ }
+
+ /**
+ * Returns the minimum amount by which an icon with {@param bounds} should be scaled
+ * so that the shadows do not get clipped.
+ */
+ public static float getScaleForBounds(RectF bounds) {
+ float scale = 1;
+
+ // For top, left & right, we need same space.
+ float minSide = Math.min(Math.min(bounds.left, bounds.right), bounds.top);
+ if (minSide < BLUR_FACTOR) {
+ scale = (HALF_DISTANCE - BLUR_FACTOR) / (HALF_DISTANCE - minSide);
+ }
+
+ float bottomSpace = BLUR_FACTOR + KEY_SHADOW_DISTANCE;
+ if (bounds.bottom < bottomSpace) {
+ scale = Math.min(scale, (HALF_DISTANCE - bottomSpace) / (HALF_DISTANCE - bounds.bottom));
+ }
+ return scale;
+ }
+}
diff --git a/src/com/android/launcher3/pageindicators/CaretDrawable.java b/src/com/android/launcher3/pageindicators/CaretDrawable.java
index 3a7fc42..fcf3d23 100644
--- a/src/com/android/launcher3/pageindicators/CaretDrawable.java
+++ b/src/com/android/launcher3/pageindicators/CaretDrawable.java
@@ -34,29 +34,43 @@
private float mCaretProgress;
- private Paint mPaint = new Paint();
+ private Paint mShadowPaint = new Paint();
+ private Paint mCaretPaint = new Paint();
private Path mPath = new Path();
- private int mInset;
public CaretDrawable(Context context) {
final Resources res = context.getResources();
- mPaint.setColor(res.getColor(R.color.all_apps_caret_color));
- mPaint.setAntiAlias(true);
- mPaint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.all_apps_caret_stroke_width));
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setStrokeCap(Paint.Cap.SQUARE);
- mPaint.setStrokeJoin(Paint.Join.MITER);
+ final int strokeWidth = res.getDimensionPixelSize(R.dimen.all_apps_caret_stroke_width);
+ final int shadowSpread = res.getDimensionPixelSize(R.dimen.all_apps_caret_shadow_spread);
- mInset = res.getDimensionPixelSize(R.dimen.all_apps_caret_inset);
+ mCaretPaint.setColor(res.getColor(R.color.all_apps_caret_color));
+ mCaretPaint.setAntiAlias(true);
+ mCaretPaint.setStrokeWidth(strokeWidth);
+ mCaretPaint.setStyle(Paint.Style.STROKE);
+ mCaretPaint.setStrokeCap(Paint.Cap.SQUARE);
+ mCaretPaint.setStrokeJoin(Paint.Join.MITER);
+
+ mShadowPaint.setColor(res.getColor(R.color.all_apps_caret_shadow_color));
+ mShadowPaint.setAntiAlias(true);
+ mShadowPaint.setStrokeWidth(strokeWidth + (shadowSpread * 2));
+ mShadowPaint.setStyle(Paint.Style.STROKE);
+ mShadowPaint.setStrokeCap(Paint.Cap.ROUND);
+ mShadowPaint.setStrokeJoin(Paint.Join.ROUND);
}
@Override
public void draw(Canvas canvas) {
- final float width = getBounds().width();
- final float height = getBounds().height();
- final float left = getBounds().left;
- final float top = getBounds().top;
+ // Assumes caret paint is more important than shadow paint
+ if (Float.compare(mCaretPaint.getAlpha(), 0f) == 0) {
+ return;
+ }
+
+ // Assumes shadow stroke width is larger
+ final float width = getBounds().width() - mShadowPaint.getStrokeWidth();
+ final float height = getBounds().height() - mShadowPaint.getStrokeWidth();
+ final float left = getBounds().left + (mShadowPaint.getStrokeWidth() / 2);
+ final float top = getBounds().top + (mShadowPaint.getStrokeWidth() / 2);
final float verticalInset = (height / 4);
final float caretHeight = (height - (verticalInset * 2));
@@ -66,7 +80,8 @@
mPath.lineTo(left + (width / 2), top + caretHeight * mCaretProgress);
mPath.lineTo(left + width, top + caretHeight * (1 - mCaretProgress));
- canvas.drawPath(mPath, mPaint);
+ canvas.drawPath(mPath, mShadowPaint);
+ canvas.drawPath(mPath, mCaretPaint);
}
@Override
@@ -78,21 +93,18 @@
@Override
public int getOpacity() {
- return PixelFormat.OPAQUE;
+ return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
- // no-op
+ mCaretPaint.setAlpha(alpha);
+ mShadowPaint.setAlpha(alpha);
+ invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter cf) {
// no-op
}
-
- @Override
- public void setBounds(int left, int top, int right, int bottom) {
- super.setBounds(left + mInset, top + mInset, right - mInset, bottom - mInset);
- }
}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
index 8075201..1eee59e 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorCaretLandscape.java
@@ -16,13 +16,19 @@
package com.android.launcher3.pageindicators;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
import android.util.AttributeSet;
import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
/**
- * Simply draws the caret drawable in the center. Used for the landscape layout.
+ * Simply draws the caret drawable bottom-right aligned in the view. This ensures that we can have
+ * a view with as large an area as we want (for touching) while maintaining a caret of size
+ * all_apps_caret_size. Used only for the landscape layout.
*/
public class PageIndicatorCaretLandscape extends PageIndicator {
// all apps pull up handle drawable.
@@ -38,7 +44,11 @@
public PageIndicatorCaretLandscape(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- setCaretDrawable(new CaretDrawable(context));
+ int caretSize = context.getResources().getDimensionPixelSize(R.dimen.all_apps_caret_size);
+ CaretDrawable caretDrawable = new CaretDrawable(context);
+ caretDrawable.setBounds(0, 0, caretSize, caretSize);
+ setCaretDrawable(caretDrawable);
+
Launcher l = (Launcher) context;
setOnTouchListener(l.getHapticFeedbackTouchListener());
setOnClickListener(l);
@@ -46,15 +56,12 @@
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- int size = bottom - top;
- int l = (right - left) / 2 - size / 2;
- getCaretDrawable().setBounds(l, 0, l + size, size);
- }
-
- @Override
protected void onDraw(Canvas canvas) {
+ Rect drawableBounds = getCaretDrawable().getBounds();
+ int count = canvas.save();
+ canvas.translate(getWidth() - drawableBounds.width(),
+ getHeight() - drawableBounds.height());
getCaretDrawable().draw(canvas);
+ canvas.restoreToCount(count);
}
}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
index f18c799..fbfb61b 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
@@ -63,6 +63,8 @@
private final int mLineHeight;
private final Rect mTouchHitRect = new Rect();
private final int mTouchExtensionHeight;
+ private final int mCaretSizePx;
+ private final int mCaretWorkspaceOffsetPx;
private static final Property<PageIndicatorLineCaret, Integer> PAINT_ALPHA
= new Property<PageIndicatorLineCaret, Integer>(Integer.class, "paint_alpha") {
@@ -123,14 +125,18 @@
public PageIndicatorLineCaret(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+
+ Resources res = context.getResources();
mLinePaint = new Paint();
mLinePaint.setAlpha(0);
+ mCaretSizePx = res.getDimensionPixelSize(R.dimen.all_apps_caret_size);
+ mCaretWorkspaceOffsetPx = res.getDimensionPixelSize(
+ R.dimen.all_apps_caret_workspace_offset);
mLauncher = (Launcher) context;
setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
setOnClickListener(mLauncher);
setOnFocusChangeListener(mLauncher.mFocusHandler);
- Resources res = context.getResources();
setCaretDrawable(new CaretDrawable(context));
mLineHeight = res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_line_height);
mTouchExtensionHeight = res.getDimensionPixelSize(
@@ -140,9 +146,10 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- int size = bottom - top;
- int l = (right - left) / 2 - size / 2;
- getCaretDrawable().setBounds(l, 0, l + size, size);
+ // Top/center align the caret in the page indicator space
+ int l = (right - left) / 2 - mCaretSizePx / 2;
+ getCaretDrawable().setBounds(l, mCaretWorkspaceOffsetPx, l + mCaretSizePx,
+ mCaretWorkspaceOffsetPx + mCaretSizePx);
// The touch area is expanded below this view by #mTouchExtensionHeight
// which extends to the top of the hotseat.
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
index 66e98cd..450c36d 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -81,11 +81,13 @@
}
/**
- * Gets all the shortcuts associated with the given package and user.
+ * Gets all the manifest and dynamic shortcuts associated with the given package and user,
+ * to be displayed in the shortcuts container on long press.
*/
- public List<ShortcutInfoCompat> queryForAllAppShortcuts(ComponentName activity,
+ public List<ShortcutInfoCompat> queryForShortcutsContainer(ComponentName activity,
List<String> ids, UserHandleCompat user) {
- return query(FLAG_GET_ALL, activity.getPackageName(), activity, ids, user);
+ return query(FLAG_MATCH_MANIFEST | FLAG_MATCH_DYNAMIC,
+ activity.getPackageName(), activity, ids, user);
}
/**
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 7997d1e..f9dd336 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -16,19 +16,32 @@
package com.android.launcher3.shortcuts;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
import android.support.annotation.IntDef;
import android.util.AttributeSet;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.LauncherViewPropertyAnimator;
import com.android.launcher3.R;
+import com.android.launcher3.util.PillRevealOutlineProvider;
/**
- * A {@link BubbleTextView} that represents a deep shortcut within an app.
+ * A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}.
+ * This lets us animate the DeepShortcutView (icon and text) separately from the background.
*/
-public class DeepShortcutView extends BubbleTextView {
+public class DeepShortcutView extends FrameLayout {
- private static final float HOVER_SCALE = 1.1f;
+ private static final float HOVER_SCALE = 1.05f;
+
// The direction this view should translate when animating the hover state.
// This allows hovered shortcuts to "push" other shortcuts away.
@IntDef({DIRECTION_UP, DIRECTION_NONE, DIRECTION_DOWN})
@@ -37,12 +50,18 @@
public static final int DIRECTION_UP = -1;
public static final int DIRECTION_NONE = 0;
public static final int DIRECTION_DOWN = 1;
+
@TranslationDirection
private int mTranslationDirection = DIRECTION_NONE;
private int mSpacing;
+ private int mRadius;
+ private Rect mPillRect;
private int mTop;
private boolean mIsHoveringOver = false;
+ private LauncherViewPropertyAnimator mHoverAnimator;
+
+ private BubbleTextView mBubbleText;
public DeepShortcutView(Context context) {
this(context, null, 0);
@@ -56,10 +75,76 @@
super(context, attrs, defStyle);
mSpacing = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_spacing);
+ mRadius = getResources().getDimensionPixelSize(R.dimen.bg_pill_radius);
+ mPillRect = new Rect();
+ mHoverAnimator = new LauncherViewPropertyAnimator(this);
}
- public int getSpacing() {
- return mSpacing;
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mBubbleText = (BubbleTextView) findViewById(R.id.deep_shortcut);
+ }
+
+ public BubbleTextView getBubbleText() {
+ return mBubbleText;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ mPillRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ }
+
+ @Override
+ public void setPivotX(float pivotX) {
+ super.setPivotX(pivotX);
+ mBubbleText.setPivotX(pivotX);
+ }
+
+ @Override
+ public void setPivotY(float pivotY) {
+ super.setPivotY(pivotY);
+ mBubbleText.setPivotY(pivotY);
+ }
+
+ /**
+ * Creates an animator to play when the shortcut container is being opened.
+ *
+ * @param animationIndex The index at which this animation will be started
+ * relative to other DeepShortcutView open animations.
+ */
+ public Animator createOpenAnimation(int animationIndex, boolean isContainerAboveIcon) {
+ final Resources res = getResources();
+ setVisibility(INVISIBLE);
+
+ AnimatorSet openAnimation = LauncherAnimUtils.createAnimatorSet();
+
+ Animator reveal = new PillRevealOutlineProvider((int) getPivotX(), (int) getPivotY(),
+ mPillRect, mRadius).createRevealAnimator(this);
+ reveal.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ setVisibility(VISIBLE);
+ }
+ });
+
+ float transY = res.getDimensionPixelSize(R.dimen.deep_shortcut_anim_translation_y);
+ Animator translationY = ObjectAnimator.ofFloat(this, TRANSLATION_Y,
+ isContainerAboveIcon ? transY : -transY, 0);
+
+ // Only scale mBubbleText (the icon and text, not the background).
+ mBubbleText.setScaleX(0);
+ mBubbleText.setScaleY(0);
+ LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(mBubbleText)
+ .scaleX(1).scaleY(1);
+
+ openAnimation.playTogether(reveal, translationY, scale);
+ openAnimation.setStartDelay(animationIndex * res.getInteger(
+ R.integer.config_deepShortcutOpenStagger));
+ openAnimation.setDuration(res.getInteger(R.integer.config_deepShortcutOpenDuration));
+ openAnimation.setInterpolator(new DecelerateInterpolator());
+ return openAnimation;
}
/**
@@ -95,16 +180,16 @@
/**
* If this shortcut is being hovered over, we scale it up. If another shortcut is being hovered
* over, we translate this one away from it to account for its increased size.
- *
- * TODO: apply motion spec here
*/
private void animateHoverState() {
+ if (mHoverAnimator.isRunning()) {
+ return;
+ }
float scale = mIsHoveringOver ? HOVER_SCALE : 1f;
- setScaleX(scale);
- setScaleY(scale);
-
- float translation = (HOVER_SCALE - 1f) * getHeight();
- setTranslationY(translation * mTranslationDirection);
+ float translateY = (HOVER_SCALE - 1f) * getHeight() * mTranslationDirection;
+ mHoverAnimator.scaleX(scale).scaleY(scale).translationY(translateY)
+ .setDuration(getResources().getInteger(R.integer.config_deepShortcutHoverDuration))
+ .start();
}
public boolean isHoveringOver() {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index d9e34a6..912f006 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -1,6 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.launcher3.shortcuts;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
@@ -12,6 +30,7 @@
import android.os.Looper;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -22,9 +41,9 @@
import com.android.launcher3.DropTarget;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LogDecelerateInterpolator;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
@@ -36,8 +55,9 @@
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.UiThreadCircularReveal;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -64,6 +84,27 @@
private Point mIconLastTouchPos = new Point();
private boolean mIsLeftAligned;
private boolean mIsAboveIcon;
+ private boolean mIsAnimatingOpen;
+
+ /**
+ * Sorts shortcuts in rank order, with manifest shortcuts coming before dynamic shortcuts.
+ */
+ private static final Comparator<ShortcutInfoCompat> sShortcutsComparator
+ = new Comparator<ShortcutInfoCompat>() {
+ @Override
+ public int compare(ShortcutInfoCompat a, ShortcutInfoCompat b) {
+ if (a.isDeclaredInManifest() && !b.isDeclaredInManifest()) {
+ return -1;
+ }
+ if (!a.isDeclaredInManifest() && b.isDeclaredInManifest()) {
+ return 1;
+ }
+ return Integer.compare(a.getRank(), b.getRank());
+ }
+ };
+
+ private static final Comparator<ShortcutInfoCompat> sShortcutsComparatorReversed
+ = Collections.reverseOrder(sShortcutsComparator);
public DeepShortcutsContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -85,11 +126,12 @@
public void populateAndShow(final BubbleTextView originalIcon, final List<String> ids) {
// Add dummy views first, and populate with real shortcut info when ready.
+ final int spacing = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_spacing);
+ final LayoutInflater inflator = mLauncher.getLayoutInflater();
for (int i = 0; i < ids.size(); i++) {
- final DeepShortcutView shortcut = (DeepShortcutView)
- mLauncher.getLayoutInflater().inflate(R.layout.deep_shortcut, this, false);
+ final View shortcut = inflator.inflate(R.layout.deep_shortcut, this, false);
if (i < ids.size() - 1) {
- ((LayoutParams) shortcut.getLayoutParams()).bottomMargin = shortcut.getSpacing();
+ ((LayoutParams) shortcut.getLayoutParams()).bottomMargin = spacing;
}
addView(shortcut);
}
@@ -109,7 +151,11 @@
@Override
public void run() {
final List<ShortcutInfoCompat> shortcuts = mDeepShortcutsManager
- .queryForAllAppShortcuts(activity, ids, user);
+ .queryForShortcutsContainer(activity, ids, user);
+ // We want the lowest rank to be closest to the user's finger.
+ final Comparator<ShortcutInfoCompat> shortcutsComparator = mIsAboveIcon ?
+ sShortcutsComparatorReversed : sShortcutsComparator;
+ Collections.sort(shortcuts, shortcutsComparator);
for (int i = 0; i < shortcuts.size(); i++) {
final ShortcutInfoCompat shortcut = shortcuts.get(i);
final ShortcutInfo launcherShortcutInfo = ShortcutInfo
@@ -139,7 +185,7 @@
@Override
public void run() {
- DeepShortcutView shortcutView = (DeepShortcutView) getChildAt(mShortcutChildIndex);
+ BubbleTextView shortcutView = getShortcutAt(mShortcutChildIndex).getBubbleText();
shortcutView.applyFromShortcutInfo(mShortcutChildInfo,
LauncherAppState.getInstance().getIconCache());
shortcutView.setText(mLabel);
@@ -149,19 +195,36 @@
}
}
- // TODO: update this animation
+ private DeepShortcutView getShortcutAt(int index) {
+ return (DeepShortcutView) getChildAt(index);
+ }
+
private void animateOpen(BubbleTextView originalIcon) {
orientAboutIcon(originalIcon);
setVisibility(View.VISIBLE);
- int rx = (int) Math.max(Math.max(getMeasuredWidth() - getPivotX(), 0), getPivotX());
- int ry = (int) Math.max(Math.max(getMeasuredHeight() - getPivotY(), 0), getPivotY());
- float radius = (float) Math.hypot(rx, ry);
- Animator reveal = UiThreadCircularReveal.createCircularReveal(this, (int) getPivotX(),
- (int) getPivotY(), 0, radius);
- reveal.setDuration(getResources().getInteger(R.integer.config_materialFolderExpandDuration));
- reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
- reveal.start();
+
+ final AnimatorSet shortcutAnims = LauncherAnimUtils.createAnimatorSet();
+ final int numShortcuts = getChildCount();
+ final int arrowOffset = getResources().getDimensionPixelSize(
+ R.dimen.deep_shortcuts_arrow_horizontal_offset);
+ final int pivotX = mIsLeftAligned ? arrowOffset : getMeasuredWidth() - arrowOffset;
+ final int pivotY = getShortcutAt(0).getMeasuredHeight() / 2;
+ for (int i = 0; i < numShortcuts; i++) {
+ DeepShortcutView deepShortcutView = getShortcutAt(i);
+ deepShortcutView.setPivotX(pivotX);
+ deepShortcutView.setPivotY(pivotY);
+ int animationIndex = mIsAboveIcon ? numShortcuts - i - 1 : i;
+ shortcutAnims.play(deepShortcutView.createOpenAnimation(animationIndex, mIsAboveIcon));
+ }
+ shortcutAnims.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingOpen = false;
+ }
+ });
+ mIsAnimatingOpen = true;
+ shortcutAnims.start();
}
/**
@@ -176,7 +239,7 @@
* So we always align left if there is enough horizontal space
* and align above if there is enough vertical space.
*
- * TODO: draw pointer based on orientation.
+ * TODO: draw arrow based on orientation.
*/
private void orientAboutIcon(BubbleTextView icon) {
int width = getMeasuredWidth();
@@ -199,9 +262,6 @@
y = mTempRect.bottom;
}
- setPivotX(width / 2);
- setPivotY(height / 2);
-
// Insets are added later, so subtract them now.
y -= insets.top;
@@ -282,8 +342,8 @@
} else {
// Determine whether touch is over a shortcut.
boolean hoveringOverShortcut = false;
- for (int i = 0; i < childCount; i++) {
- DeepShortcutView shortcut = (DeepShortcutView) getChildAt(i);
+ for (int i = 0; i < childCount && !mIsAnimatingOpen; i++) {
+ DeepShortcutView shortcut = getShortcutAt(i);
if (shortcut.updateHoverState(containerContainsTouch, hoveringOverShortcut, y)) {
hoveringOverShortcut = true;
}
@@ -307,9 +367,9 @@
cleanupDeferredDrag();
// Launch a shortcut if user was hovering over it.
for (int i = 0; i < childCount; i++) {
- DeepShortcutView shortcut = (DeepShortcutView) getChildAt(i);
+ DeepShortcutView shortcut = getShortcutAt(i);
if (shortcut.isHoveringOver()) {
- shortcut.performClick();
+ shortcut.getBubbleText().performClick();
break;
}
}
diff --git a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
index 8dbeaa7..00553df 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
@@ -97,6 +97,14 @@
return mShortcutInfo.isPinned();
}
+ public boolean isDeclaredInManifest() {
+ return mShortcutInfo.isDeclaredInManifest();
+ }
+
+ public int getRank() {
+ return mShortcutInfo.getRank();
+ }
+
@Override
public String toString() {
return mShortcutInfo.toString();
diff --git a/src/com/android/launcher3/shortcuts/ShortcutKey.java b/src/com/android/launcher3/shortcuts/ShortcutKey.java
index c9d66eb..c15f91d 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutKey.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutKey.java
@@ -2,7 +2,6 @@
import android.content.ComponentName;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.ComponentKey;
@@ -22,9 +21,4 @@
return new ShortcutKey(shortcutInfo.getPackage(), shortcutInfo.getUserHandle(),
shortcutInfo.getId());
}
-
- @Override
- public String toString() {
- return flattenToString(LauncherAppState.getInstance().getContext());
- }
}
diff --git a/src/com/android/launcher3/util/CircleRevealOutlineProvider.java b/src/com/android/launcher3/util/CircleRevealOutlineProvider.java
new file mode 100644
index 0000000..c192120
--- /dev/null
+++ b/src/com/android/launcher3/util/CircleRevealOutlineProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class CircleRevealOutlineProvider extends RevealOutlineAnimation {
+
+ private int mCenterX;
+ private int mCenterY;
+ private float mRadius0;
+ private float mRadius1;
+
+ /**
+ * @param x reveal center x
+ * @param y reveal center y
+ * @param r0 initial radius
+ * @param r1 final radius
+ */
+ public CircleRevealOutlineProvider(int x, int y, float r0, float r1) {
+ mCenterX = x;
+ mCenterY = y;
+ mRadius0 = r0;
+ mRadius1 = r1;
+ }
+
+ @Override
+ public boolean shouldRemoveElevationDuringAnimation() {
+ return true;
+ }
+
+ @Override
+ public void setProgress(float progress) {
+ mOutlineRadius = (1 - progress) * mRadius0 + progress * mRadius1;
+
+ mOutline.left = (int) (mCenterX - mOutlineRadius);
+ mOutline.top = (int) (mCenterY - mOutlineRadius);
+ mOutline.right = (int) (mCenterX + mOutlineRadius);
+ mOutline.bottom = (int) (mCenterY + mOutlineRadius);
+ }
+}
diff --git a/src/com/android/launcher3/util/ComponentKey.java b/src/com/android/launcher3/util/ComponentKey.java
index b7aafae..144b411 100644
--- a/src/com/android/launcher3/util/ComponentKey.java
+++ b/src/com/android/launcher3/util/ComponentKey.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.content.Context;
+
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
@@ -60,17 +61,6 @@
mHashCode = Arrays.hashCode(new Object[] {componentName, user});
}
- /**
- * Encodes a component key as a string of the form [flattenedComponentString#userId].
- */
- public String flattenToString(Context context) {
- String flattened = componentName.flattenToString();
- if (user != null) {
- flattened += "#" + UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
- }
- return flattened;
- }
-
@Override
public int hashCode() {
return mHashCode;
@@ -81,4 +71,12 @@
ComponentKey other = (ComponentKey) o;
return other.componentName.equals(componentName) && other.user.equals(user);
}
+
+ /**
+ * Encodes a component key as a string of the form [flattenedComponentString#userId].
+ */
+ @Override
+ public String toString() {
+ return componentName.flattenToString() + "#" + user;
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/IconNormalizer.java b/src/com/android/launcher3/util/IconNormalizer.java
index 4087d7b..040a1b5 100644
--- a/src/com/android/launcher3/util/IconNormalizer.java
+++ b/src/com/android/launcher3/util/IconNormalizer.java
@@ -19,6 +19,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import com.android.launcher3.LauncherAppState;
@@ -74,8 +75,10 @@
*
* This closeness is used to determine the ratio of hull area to the full icon size.
* Refer {@link #MAX_CIRCLE_AREA_FACTOR} and {@link #MAX_SQUARE_AREA_FACTOR}
+ *
+ * @param outBounds optional rect to receive the fraction distance from each edge.
*/
- public synchronized float getScale(Drawable d) {
+ public synchronized float getScale(Drawable d, RectF outBounds) {
int width = d.getIntrinsicWidth();
int height = d.getIntrinsicHeight();
if (width <= 0 || height <= 0) {
@@ -168,6 +171,14 @@
scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
}
+ if (outBounds != null) {
+ outBounds.left = ((float) leftX) / width;
+ outBounds.right = 1 - ((float) rightX) / width;
+
+ outBounds.top = ((float) topY) / height;
+ outBounds.bottom = 1 - ((float) bottomY) / height;
+ }
+
float areaScale = area / (width * height);
// Use sqrt of the final ratio as the images is scaled across both width and height.
float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
diff --git a/src/com/android/launcher3/util/PillRevealOutlineProvider.java b/src/com/android/launcher3/util/PillRevealOutlineProvider.java
new file mode 100644
index 0000000..09ff9bd
--- /dev/null
+++ b/src/com/android/launcher3/util/PillRevealOutlineProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.annotation.TargetApi;
+import android.graphics.Rect;
+import android.os.Build;
+import android.view.ViewOutlineProvider;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+/**
+ * A {@link ViewOutlineProvider} that animates a reveal in a "pill" shape.
+ * A pill is simply a round rect, but we assume the width is greater than
+ * the height and that the radius is equal to half the height.
+ */
+public class PillRevealOutlineProvider extends RevealOutlineAnimation {
+
+ private int mCenterX;
+ private int mCenterY;
+ private Rect mPillRect;
+
+ /**
+ * @param x reveal center x
+ * @param y reveal center y
+ * @param pillRect round rect that represents the final pill shape
+ * @param pillRectRadius radius of the round rect
+ */
+ public PillRevealOutlineProvider(int x, int y, Rect pillRect, float pillRectRadius) {
+ mCenterX = x;
+ mCenterY = y;
+ mPillRect = pillRect;
+ mOutlineRadius = pillRectRadius;
+ }
+
+ @Override
+ public boolean shouldRemoveElevationDuringAnimation() {
+ return false;
+ }
+
+ @Override
+ public void setProgress(float progress) {
+ // Assumes width is greater than height.
+ int centerToEdge = Math.max(mCenterX, mPillRect.width() - mCenterX);
+ int currentSize = (int) (progress * centerToEdge);
+
+ // Bound the outline to the final pill shape defined by mPillRect.
+ mOutline.left = Math.max(mPillRect.left, mCenterX - currentSize);
+ mOutline.top = Math.max(mPillRect.top, mCenterY - currentSize);
+ mOutline.right = Math.min(mPillRect.right, mCenterX + currentSize);
+ mOutline.bottom = Math.min(mPillRect.bottom, mCenterY + currentSize);
+ }
+}
diff --git a/src/com/android/launcher3/util/RevealOutlineAnimation.java b/src/com/android/launcher3/util/RevealOutlineAnimation.java
new file mode 100644
index 0000000..4447c3b
--- /dev/null
+++ b/src/com/android/launcher3/util/RevealOutlineAnimation.java
@@ -0,0 +1,72 @@
+package com.android.launcher3.util;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import com.android.launcher3.Utilities;
+
+/**
+ * A {@link ViewOutlineProvider} that has helper functions to create reveal animations.
+ * This class should be extended so that subclasses can define the reveal shape as the
+ * animation progresses from 0 to 1.
+ */
+public abstract class RevealOutlineAnimation extends ViewOutlineProvider {
+ protected Rect mOutline;
+ protected float mOutlineRadius;
+
+ public RevealOutlineAnimation() {
+ mOutline = new Rect();
+ }
+
+ /** Returns whether elevation should be removed for the duration of the reveal animation. */
+ abstract boolean shouldRemoveElevationDuringAnimation();
+ /** Sets the progress, from 0 to 1, of the reveal animation. */
+ abstract void setProgress(float progress);
+
+ public ValueAnimator createRevealAnimator(final View revealView) {
+ ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+ final float elevation = revealView.getElevation();
+
+ va.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationStart(Animator animation) {
+ revealView.setOutlineProvider(RevealOutlineAnimation.this);
+ revealView.setClipToOutline(true);
+ if (shouldRemoveElevationDuringAnimation()) {
+ revealView.setTranslationZ(-elevation);
+ }
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ revealView.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
+ revealView.setClipToOutline(false);
+ if (shouldRemoveElevationDuringAnimation()) {
+ revealView.setTranslationZ(0);
+ }
+ }
+
+ });
+
+ va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator arg0) {
+ float progress = arg0.getAnimatedFraction();
+ setProgress(progress);
+ revealView.invalidateOutline();
+ if (!Utilities.ATLEAST_LOLLIPOP_MR1) {
+ revealView.invalidate();
+ }
+ }
+ });
+ return va;
+ }
+
+ @Override
+ public void getOutline(View v, Outline outline) {
+ outline.setRoundRect(mOutline, mOutlineRadius);
+ }
+}
diff --git a/src/com/android/launcher3/util/RevealOutlineProvider.java b/src/com/android/launcher3/util/RevealOutlineProvider.java
deleted file mode 100644
index 0db3984..0000000
--- a/src/com/android/launcher3/util/RevealOutlineProvider.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.android.launcher3.util;
-
-import android.annotation.TargetApi;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.os.Build;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class RevealOutlineProvider extends ViewOutlineProvider {
-
- private int mCenterX;
- private int mCenterY;
- private float mRadius0;
- private float mRadius1;
- private int mCurrentRadius;
-
- private final Rect mOval;
-
- /**
- * @param x reveal center x
- * @param y reveal center y
- * @param r0 initial radius
- * @param r1 final radius
- */
- public RevealOutlineProvider(int x, int y, float r0, float r1) {
- mCenterX = x;
- mCenterY = y;
- mRadius0 = r0;
- mRadius1 = r1;
-
- mOval = new Rect();
- }
-
- public void setProgress(float progress) {
- mCurrentRadius = (int) ((1 - progress) * mRadius0 + progress * mRadius1);
-
- mOval.left = mCenterX - mCurrentRadius;
- mOval.top = mCenterY - mCurrentRadius;
- mOval.right = mCenterX + mCurrentRadius;
- mOval.bottom = mCenterY + mCurrentRadius;
- }
-
- @Override
- public void getOutline(View v, Outline outline) {
- outline.setRoundRect(mOval, mCurrentRadius);
- }
-}
diff --git a/src/com/android/launcher3/util/UiThreadCircularReveal.java b/src/com/android/launcher3/util/UiThreadCircularReveal.java
deleted file mode 100644
index f2b5e5e..0000000
--- a/src/com/android/launcher3/util/UiThreadCircularReveal.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.android.launcher3.util;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.TargetApi;
-import android.os.Build;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-
-import com.android.launcher3.Utilities;
-
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-public class UiThreadCircularReveal {
-
- public static ValueAnimator createCircularReveal(View v, int x, int y, float r0, float r1) {
- return createCircularReveal(v, x, y, r0, r1, ViewOutlineProvider.BACKGROUND);
- }
-
- public static ValueAnimator createCircularReveal(View v, int x, int y, float r0, float r1,
- final ViewOutlineProvider originalProvider) {
- ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-
- final View revealView = v;
- final RevealOutlineProvider outlineProvider = new RevealOutlineProvider(x, y, r0, r1);
- final float elevation = v.getElevation();
-
- va.addListener(new AnimatorListenerAdapter() {
- public void onAnimationStart(Animator animation) {
- revealView.setOutlineProvider(outlineProvider);
- revealView.setClipToOutline(true);
- revealView.setTranslationZ(-elevation);
- }
-
- public void onAnimationEnd(Animator animation) {
- revealView.setOutlineProvider(originalProvider);
- revealView.setClipToOutline(false);
- revealView.setTranslationZ(0);
- }
-
- });
-
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator arg0) {
- float progress = arg0.getAnimatedFraction();
- outlineProvider.setProgress(progress);
- revealView.invalidateOutline();
- if (!Utilities.ATLEAST_LOLLIPOP_MR1) {
- revealView.invalidate();
- }
- }
- });
- return va;
- }
-}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 8a58d34..34bee1b 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -20,7 +20,6 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView.State;
import android.util.AttributeSet;
@@ -32,7 +31,6 @@
import com.android.launcher3.BaseContainerView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeleteDropTarget;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.folder.Folder;
@@ -62,6 +60,9 @@
private DragController mDragController;
private IconCache mIconCache;
+ private final Rect mTmpBgPaddingRect = new Rect();
+ private final Rect mTmpRect = new Rect();
+
/* Recycler view related member variables */
private WidgetsRecyclerView mRecyclerView;
private WidgetsListAdapter mAdapter;
@@ -97,18 +98,24 @@
mRecyclerView = (WidgetsRecyclerView) getContentView().findViewById(R.id.widgets_list_view);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+ }
- Rect bgPadding = new Rect();
- getRevealView().getBackground().getPadding(bgPadding);
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ getRevealView().getBackground().getPadding(mTmpBgPaddingRect);
if (Utilities.isRtl(getResources())) {
- getContentView().setPadding(0, bgPadding.top,
- bgPadding.right, bgPadding.bottom);
- mRecyclerView.updateBackgroundPadding(new Rect(bgPadding.left, 0, 0, 0));
+ getContentView().setPadding(0, mTmpBgPaddingRect.top, mTmpBgPaddingRect.right,
+ mTmpBgPaddingRect.bottom);
+ mTmpRect.set(mTmpBgPaddingRect.left, 0, 0, 0);
+ mRecyclerView.updateBackgroundPadding(mTmpRect);
} else {
- getContentView().setPadding(bgPadding.left, bgPadding.top,
- 0, bgPadding.bottom);
- mRecyclerView.updateBackgroundPadding(new Rect(0, 0, bgPadding.right, 0));
+ getContentView().setPadding(mTmpBgPaddingRect.left, mTmpBgPaddingRect.top, 0,
+ mTmpBgPaddingRect.bottom);
+ mTmpRect.set(0, 0, mTmpBgPaddingRect.right, 0);
+ mRecyclerView.updateBackgroundPadding(mTmpRect);
}
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
//