Merge "Launcher-side changes to support prediction bar." into ub-launcher3-burnaby
diff --git a/proguard.flags b/proguard.flags
index e2a4b5b..6eb5948 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -65,4 +65,8 @@
-keep class com.android.launcher3.AppsContainerRecyclerView {
public void setFastScrollerAlpha(float);
public float getFastScrollerAlpha();
-}
\ No newline at end of file
+}
+
+-keep class com.android.launcher3.ButtonDropTarget {
+ public int getTextColor();
+}
diff --git a/res/drawable-hdpi/ic_launcher_clear_active_holo.png b/res/drawable-hdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index cdd0052..0000000
--- a/res/drawable-hdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_clear_normal_holo.png b/res/drawable-hdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index 84549ff..0000000
--- a/res/drawable-hdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_active.png b/res/drawable-hdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..f7a3b68
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_active_holo.png b/res/drawable-hdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index c534e56..0000000
--- a/res/drawable-hdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_normal.png b/res/drawable-hdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..780d796
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_normal_holo.png b/res/drawable-hdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index c9bcd7f..0000000
--- a/res/drawable-hdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_remove_active.png b/res/drawable-hdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..e53de0d
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_remove_normal.png b/res/drawable-hdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..91e19ca
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 82b1b59..0000000
--- a/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 3fc2e83..0000000
--- a/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_uninstall_active.png b/res/drawable-hdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..22b97ee
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_uninstall_normal.png b/res/drawable-hdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..7aea5d0
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_clear_active_holo.png b/res/drawable-mdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 2683bea..0000000
--- a/res/drawable-mdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_clear_normal_holo.png b/res/drawable-mdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index 219f3e5..0000000
--- a/res/drawable-mdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_active.png b/res/drawable-mdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..ea71272
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_active_holo.png b/res/drawable-mdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index f84b4a6..0000000
--- a/res/drawable-mdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_normal.png b/res/drawable-mdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..8c60159
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_normal_holo.png b/res/drawable-mdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index eac578f..0000000
--- a/res/drawable-mdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_remove_active.png b/res/drawable-mdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..f36cfdd
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_remove_normal.png b/res/drawable-mdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..60829b9
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 0350e55..0000000
--- a/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 799b62f..0000000
--- a/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_uninstall_active.png b/res/drawable-mdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..e4ee911
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_uninstall_normal.png b/res/drawable-mdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..aefbc69
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_clear_active_holo.png b/res/drawable-xhdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 1a7e53d..0000000
--- a/res/drawable-xhdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png b/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index d4965d9..0000000
--- a/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_active.png b/res/drawable-xhdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..b438f9e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_active_holo.png b/res/drawable-xhdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index b8cdbc4..0000000
--- a/res/drawable-xhdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_normal.png b/res/drawable-xhdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..5c49816
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_normal_holo.png b/res/drawable-xhdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index f503fb8..0000000
--- a/res/drawable-xhdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_remove_active.png b/res/drawable-xhdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..14ac79d
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_remove_normal.png b/res/drawable-xhdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..8188805
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index c155274..0000000
--- a/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 2ec7ad9..0000000
--- a/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_uninstall_active.png b/res/drawable-xhdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..2c19b32
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xhdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..a093f28
--- /dev/null
+++ b/res/drawable-xhdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png b/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 95cf841..0000000
--- a/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index b0f5a27..0000000
--- a/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_active.png b/res/drawable-xxhdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..d354dd3
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_active_holo.png b/res/drawable-xxhdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index 57f332a..0000000
--- a/res/drawable-xxhdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_normal.png b/res/drawable-xxhdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..c270be2
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index 94f0955..0000000
--- a/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_remove_active.png b/res/drawable-xxhdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..9df4404
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_remove_normal.png b/res/drawable-xxhdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..5bc8f0c
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 3bb098c..0000000
--- a/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 550cc5b..0000000
--- a/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_uninstall_active.png b/res/drawable-xxhdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..db7d339
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..4fce55b
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_info_active.png b/res/drawable-xxxhdpi/ic_launcher_info_active.png
new file mode 100644
index 0000000..162e23d
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_info_active.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_info_normal.png b/res/drawable-xxxhdpi/ic_launcher_info_normal.png
new file mode 100644
index 0000000..270e15d
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_info_normal.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_remove_active.png b/res/drawable-xxxhdpi/ic_launcher_remove_active.png
new file mode 100644
index 0000000..c0b8ea2
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_remove_active.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_remove_normal.png b/res/drawable-xxxhdpi/ic_launcher_remove_normal.png
new file mode 100644
index 0000000..ed96c55
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_remove_normal.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png b/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png
new file mode 100644
index 0000000..75896f3
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png b/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png
new file mode 100644
index 0000000..61490b9
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_launcher_uninstall_normal.png
Binary files differ
diff --git a/res/drawable/info_target_selector.xml b/res/drawable/info_target_selector.xml
index f3a7016..51caece 100644
--- a/res/drawable/info_target_selector.xml
+++ b/res/drawable/info_target_selector.xml
@@ -19,6 +19,6 @@
-->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_launcher_info_normal_holo" />
- <item android:drawable="@drawable/ic_launcher_info_active_holo" />
+ <item android:drawable="@drawable/ic_launcher_info_normal" />
+ <item android:drawable="@drawable/ic_launcher_info_active" />
</transition>
diff --git a/res/drawable/remove_target_selector.xml b/res/drawable/remove_target_selector.xml
index 5e071fb..9025e8a 100644
--- a/res/drawable/remove_target_selector.xml
+++ b/res/drawable/remove_target_selector.xml
@@ -19,6 +19,6 @@
-->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_launcher_clear_normal_holo" />
- <item android:drawable="@drawable/ic_launcher_clear_active_holo" />
+ <item android:drawable="@drawable/ic_launcher_remove_normal" />
+ <item android:drawable="@drawable/ic_launcher_remove_active" />
</transition>
diff --git a/res/drawable/uninstall_target_selector.xml b/res/drawable/uninstall_target_selector.xml
index 229942e..175cc20 100644
--- a/res/drawable/uninstall_target_selector.xml
+++ b/res/drawable/uninstall_target_selector.xml
@@ -19,6 +19,6 @@
-->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_launcher_trashcan_normal_holo" />
- <item android:drawable="@drawable/ic_launcher_trashcan_active_holo" />
+ <item android:drawable="@drawable/ic_launcher_uninstall_normal" />
+ <item android:drawable="@drawable/ic_launcher_uninstall_active" />
</transition>
diff --git a/res/layout/add_list_item.xml b/res/layout/add_list_item.xml
deleted file mode 100644
index e937d7b..0000000
--- a/res/layout/add_list_item.xml
+++ /dev/null
@@ -1,25 +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.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:gravity="center_vertical"
- android:drawablePadding="14dip"
- android:paddingLeft="15dip"
- android:paddingRight="15dip" />
diff --git a/res/layout/rename_folder.xml b/res/layout/rename_folder.xml
deleted file mode 100644
index 21a335c..0000000
--- a/res/layout/rename_folder.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="20dip"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/label"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/rename_folder_label"
- android:gravity="start"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <EditText
- android:id="@+id/folder_name"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:scrollHorizontally="true"
- android:autoText="false"
- android:capitalize="none"
- android:gravity="fill_horizontal"
- android:maxLength="30"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
-</LinearLayout>
diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml
index fe18edc..69f42bb 100644
--- a/res/layout/search_drop_target_bar.xml
+++ b/res/layout/search_drop_target_bar.xml
@@ -17,8 +17,7 @@
<com.android.launcher3.SearchDropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:focusable="false"
- android:orientation="horizontal" >
+ android:focusable="false" >
<!-- Drag specific targets container -->
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 64ddea1..ab23b84 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -17,13 +17,11 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/widget_preview_container_width"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/widget_cell_height"
android:layout_weight="1"
- android:layout_marginTop="@dimen/widget_preview_padding_top"
- android:layout_marginLeft="8dp"
- android:layout_marginBottom="8dp"
+ android:layout_marginRight="@dimen/widget_row_divider"
android:orientation="vertical"
- android:background="@color/bubble_dark_background"
+ android:background="@color/widgets_cell_color"
android:focusable="true">
<LinearLayout
@@ -46,7 +44,7 @@
android:ellipsize="end"
android:fadingEdge="horizontal"
- android:textColor="#FFFFFFFF"
+ android:textColor="@color/widgets_view_item_text_color"
android:textSize="16sp"
android:textAlignment="viewStart"
android:fontFamily="sans-serif-condensed"
@@ -63,7 +61,7 @@
android:layout_marginLeft="5dp"
android:layout_weight="0"
android:gravity="start"
- android:textColor="#FFFFFFFF"
+ android:textColor="@color/widgets_view_item_text_color"
android:textSize="16sp"
android:textAlignment="viewStart"
android:fontFamily="sans-serif-condensed"
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index f94d023..12f6401 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -20,7 +20,6 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusable="true"
- android:background="@drawable/focusable_view_bg"
android:descendantFocusability="afterDescendants">
<!-- Section info -->
@@ -29,24 +28,23 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:focusable="true"
- android:background="@drawable/focusable_view_bg"
android:descendantFocusability="afterDescendants">
<ImageView
android:id="@+id/section_image"
- android:layout_width="@dimen/widget_section_height"
android:layout_height="@dimen/widget_section_height"
- android:paddingLeft="@dimen/widget_section_icon_padding"
- android:paddingRight="@dimen/widget_section_icon_padding"
- android:paddingTop="@dimen/widget_section_icon_padding"
- android:paddingBottom="@dimen/widget_section_icon_padding"
+ android:layout_width="@dimen/widget_section_icon_width"
+ android:paddingLeft="@dimen/widget_section_icon_horizontal_padding"
+ android:paddingRight="@dimen/widget_section_icon_horizontal_padding"
+ android:paddingTop="@dimen/widget_section_icon_vertical_padding"
+ android:paddingBottom="@dimen/widget_section_icon_vertical_padding"
android:background="@color/widget_text_panel"
/>
<TextView
android:id="@+id/section"
android:layout_width="match_parent"
android:layout_height="@dimen/widget_section_height"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
+ android:paddingEnd="@dimen/widget_preview_label_horizontal_padding"
+ android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
android:singleLine="true"
android:ellipsize="end"
android:gravity="start|center_vertical"
@@ -57,31 +55,24 @@
</LinearLayout>
<!-- Widget list -->
- <RelativeLayout
+ <RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end"
+ android:background="@color/widgets_cell_color"
>
- <!-- TODO(hyunyoungs): replace the indicator with actual assets. -->
- <FrameLayout
- android:id="@+id/scrollable_indicator"
- android:layout_gravity="center_vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/ic_pageindicator_default"
- android:visibility="invisible"
- />
<HorizontalScrollView
android:id="@+id/widgets_scroll_container"
android:layout_width="match_parent"
android:layout_height="@dimen/widget_cell_height"
- android:paddingLeft="40dp"
+ android:layout_marginLeft="@dimen/widget_row_padding"
android:scrollbars="none" >
<LinearLayout
android:id="@+id/widgets_cell_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal" />
+ android:orientation="horizontal"
+ android:background="@color/widget_text_panel"/>
</HorizontalScrollView>
</RelativeLayout>
</LinearLayout>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 3a06bd9..0c3714b 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -20,8 +20,9 @@
<resources>
<!-- The color tints to apply to the text and drag view when hovering
over the delete target or the info target -->
- <color name="delete_target_hover_tint">#DAFF0000</color>
- <color name="info_target_hover_tint">#DA0099CC</color>
+ <color name="delete_target_hover_tint">#DAC1C1C1</color>
+ <color name="uninstall_target_hover_tint">#DAF0592B</color>
+ <color name="info_target_hover_tint">#DA009688</color>
<color name="cling_scrim_background">#80000000</color>
<color name="bubble_dark_background">#20000000</color>
@@ -41,5 +42,7 @@
<color name="apps_view_section_text_color">#009688</color>
<!-- Widgetss view -->
- <color name="widgets_view_section_text_color">#009688</color>
+ <color name="widgets_view_section_text_color">#FFFFFF</color>
+ <color name="widgets_view_item_text_color">#C4C4C4</color>
+ <color name="widgets_cell_color">#263238</color>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 47394a1..7ce4059 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -55,9 +55,6 @@
<integer name="config_appsCustomizeDragSlopeThreshold">150</integer>
<!-- Workspace -->
- <!-- The transition duration for the background of the drop targets -->
- <integer name="config_dropTargetBgTransitionDuration">0</integer>
-
<!-- The duration (in ms) of the fade animation on the object outlines, used when
we are dragging objects around on the home screen. -->
<integer name="config_dragOutlineFadeTime">900</integer>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index da11082..a57ae89 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -86,12 +86,16 @@
<dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
<dimen name="widget_preview_horizontal_padding">8dp</dimen>
- <dimen name="widget_section_height">52dp</dimen>
- <dimen name="widget_section_icon_padding">8dp</dimen>
+ <dimen name="widget_section_height">56dp</dimen>
+ <dimen name="widget_section_icon_width">72dp</dimen>
+ <dimen name="widget_section_icon_vertical_padding">8dp</dimen>
+ <dimen name="widget_section_icon_horizontal_padding">16dp</dimen>
<!-- Equation: widget_preview_size + 2 * widget_preview_padding_horizontal -->
<dimen name="widget_preview_container_width">136dp</dimen>
<dimen name="widget_cell_height">150dp</dimen>
+ <dimen name="widget_row_padding">8dp</dimen>
+ <dimen name="widget_row_divider">1dp</dimen>
<!-- Padding applied to shortcut previews -->
<dimen name="shortcut_preview_padding_left">0dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bfe7e36..a5a681a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -34,8 +34,6 @@
<string name="application_name">Launcher3</string>
<!-- Accessibility-facing application name -->
<string name="home">Home</string>
- <!-- Name for all applications running as this uid. -->
- <string name="uid_name">Android Core Apps</string>
<!-- Default folder name -->
<string name="folder_name"></string>
<!-- Work folder name -->
@@ -48,10 +46,6 @@
<string name="safemode_shortcut_error">Downloaded app disabled in Safe mode</string>
<!-- SafeMode widget error string -->
<string name="safemode_widget_error">Widgets disabled in Safe mode</string>
- <!-- Labels for the tabs in the customize drawer -->
- <string name="widgets_tab_label">Widgets</string>
-
- <string name="widget_adder">Widgets</string>
<string name="toggle_weight_watcher">Show Mem</string>
@@ -62,75 +56,26 @@
<!-- There is a special version of this format string for Farsi -->
<string name="widget_dims_format">%1$d \u00d7 %2$d</string>
- <!-- External-drop widget pick label format string [CHAR_LIMIT=25] -->
- <string name="external_drop_widget_pick_format" translatable="false">%1$s (%2$d \u00d7 %3$d)</string>
- <!-- External-drop widget error string. This is the error that is shown
- when you drag and item into the homescreen and it is unable to fit,
- or an error is encountered. [CHAR_LIMIT=50] -->
- <string name="external_drop_widget_error">Couldn\'t drop item on this Home screen.</string>
- <!-- External-drop widget pick title. This is shown as the title of the
- dialog which allows you to pick which widgets to handle a particular
- drop if there are multiple choices. [CHAR_LIMIT=35] -->
- <string name="external_drop_widget_pick_title">Choose widget to create</string>
-
<!-- Apps view -->
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
<string name="apps_view_search_bar_hint">Search Apps</string>
<!-- Loading apps text. [CHAR_LIMIT=50] -->
- <string name="loading_apps_message">Loading Apps...</string>
+ <string name="loading_apps_message">Loading Apps…</string>
<!-- No-search-results text. [CHAR_LIMIT=50] -->
<string name="apps_view_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
- <!-- Folders -->
+ <!-- Drag and drop -->
<skip />
- <!-- Label of Folder name field in Rename folder dialog box -->
- <string name="rename_folder_label">Folder name</string>
- <!-- Title of dialog box -->
- <string name="rename_folder_title">Rename folder</string>
- <!-- Buttons in Rename folder dialog box -->
- <string name="rename_action">OK</string>
- <!-- Buttons in Rename folder dialog box -->
- <string name="cancel_action">Cancel</string>
- <!-- Label for button to sort folder contents. [CHAR_LIMIT=10] -->
- <string name="sort_alphabetical">A-Z</string>
-
- <!-- Shortcuts -->
- <skip />
- <!-- Title of dialog box -->
- <string name="menu_item_add_item">Add to Home screen</string>
- <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all apps -->
- <string name="group_applications">Apps</string>
- <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all shortcut
-s -->
- <string name="group_shortcuts">Shortcuts</string>
- <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets/gadgets -->
- <string name="group_widgets">Widgets</string>
- <!-- Error message when user has filled all their home screens -->
- <string name="completely_out_of_space">No more room on your Home screens.</string>
<!-- Error message when user has filled a home screen -->
<string name="out_of_space">No more room on this Home screen.</string>
<!-- Error message when user has filled the hotseat -->
<string name="hotseat_out_of_space">No more room in the Favorites tray</string>
- <!-- Error message when user tries to drop an invalid item on the hotseat -->
- <string name="invalid_hotseat_item">This widget is too large for the Favorites tray</string>
- <!-- Message displayed when a shortcut is created by an external application -->
- <string name="shortcut_installed">Shortcut \"<xliff:g id="name" example="Browser">%s</xliff:g>\" created.</string>
- <!-- Message displayed when an external application attemps to create a shortcut that already exists -->
- <string name="shortcut_duplicate">Shortcut \"<xliff:g id="name" example="Browser">%s</xliff:g>\" already exists.</string>
-
- <!-- Title of dialog when user is selecting shortcut to add to homescreen -->
- <string name="title_select_shortcut">Choose shortcut</string>
- <!-- Title of dialog when user is selecting an application to add to homescreen -->
- <string name="title_select_application">Choose app</string>
<!-- All applications label -->
<string name="all_apps_button_label">Apps</string>
<!-- Label for button in all applications label to go back home (to the workspace / desktop)
for accessibilty (spoken when the button gets focus). -->
<string name="all_apps_home_button_label">Home</string>
- <!-- Label for trash icon in All Apps. The icon/widget will become completely unavailable on the
- device. [CHAR_LIMIT=30]-->
- <string name="delete_zone_label_all_apps">Uninstall</string>
<!-- Label for delete drop target. [CHAR_LIMIT=20] -->
<string name="delete_target_label">Remove</string>
@@ -139,35 +84,6 @@
<!-- Label for the info icon. [CHAR_LIMIT=20] -->
<string name="info_target_label">App info</string>
- <!-- Accessibility: AllApps button -->
- <string name="accessibility_all_apps_button">Apps</string>
- <!-- Accessibility: Delete button -->
- <string name="accessibility_delete_button">Remove</string>
-
- <!-- Label for trash icon in All Apps, when an updated system app is selected. The update will
- be uninstalled. [CHAR_LIMIT=30] -->
- <string name="delete_zone_label_all_apps_system_app">Uninstall update</string>
-
- <!-- URL pointing to help text. If empty, no link to help will be created [DO NOT TRANSLATE] -->
- <string name="help_url" translatable="false"></string>
-
- <!-- Strings for the contextual action bar (CAB) in All Apps -->
- <skip />
- <!-- Describes the button for uninstalling the currently selected application.
- Text is not displayed, but provided for accessibility. [CHAR_LIMIT=none] -->
- <string name="cab_menu_delete_app">Uninstall app</string>
- <!-- Describes the button for getting details/info about currently selected application.
- Text is not displayed, but provided for accessibility. [CHAR_LIMIT=none] -->
- <string name="cab_menu_app_info">App details</string>
- <!-- Appears in the CAB when an app is selected in All Apps or Customize mode. [CHAR_LIMIT=50] -->
- <string name="cab_app_selection_text">1 app selected</string>
- <!-- Appears in the CAB when a widget is selected in Customize mode. [CHAR_LIMIT=50] -->
- <string name="cab_widget_selection_text">1 widget selected</string>
- <!-- Appears in the CAB when a folder is selected in Customize mode. [CHAR_LIMIT=50] -->
- <string name="cab_folder_selection_text">1 folder selected</string>
- <!-- Appears in the CAB when a shortcut is selected in Customize mode. [CHAR_LIMIT=50] -->
- <string name="cab_shortcut_selection_text">1 shortcut selected</string>
-
<!-- Permissions: -->
<skip />
<!-- Permission short label -->
@@ -198,9 +114,6 @@
<!-- Text to inform the user that they can't uninstall a system application -->
<string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>
- <!-- Title of the Android Dreams (screensaver) module -->
- <string name="dream_name">Rocket Launcher</string>
-
<!-- Default folder title -->
<string name="folder_hint_text">Unnamed Folder</string>
@@ -214,22 +127,10 @@
<string name="default_scroll_format">Page %1$d of %2$d</string>
<!-- The format string for Workspace page scroll text [CHAR_LIMIT=none] -->
<string name="workspace_scroll_format">Home screen %1$d of %2$d</string>
- <!-- The format string for AppsCustomize Apps page scroll text [CHAR_LIMIT=none] -->
- <string name="apps_customize_apps_scroll_format">Apps page %1$d of %2$d</string>
- <!-- The format string for AppsCustomize Apps page scroll text [CHAR_LIMIT=none] -->
- <string name="apps_customize_widgets_scroll_format">Widgets page %1$d of %2$d</string>
<!-- Clings -->
<!-- The title text for the workspace cling [CHAR_LIMIT=30] -->
<string name="first_run_cling_title">Welcome</string>
- <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
- <string name="first_run_cling_description">Make yourself at home.</string>
- <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
- <string name="first_run_cling_custom_content_hint"></string>
- <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
- <string name="first_run_cling_search_bar_hint"></string>
- <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
- <string name="first_run_cling_create_screens_hint">Create more screens for apps and folders</string>
<!-- The title text for the migration cling [CHAR_LIMIT=30] -->
<string name="migration_cling_title">Copy your app icons</string>
<!-- The description of what migration does [CHAR_LIMIT=70] -->
@@ -238,24 +139,14 @@
<string name="migration_cling_copy_apps">COPY ICONS</string>
<!-- The description of the button to use the default launcher layout [CHAR_LIMIT=30] -->
<string name="migration_cling_use_default">START FRESH</string>
- <!-- The title text for the workspace cling [CHAR_LIMIT=30] -->
- <string name="workspace_cling_title">Organize your space</string>
- <!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
- <string name="workspace_cling_move_item">Touch & hold background to manage wallpaper, widgets and settings.</string>
<!-- The title text for workspace longpress action [CHAR_LIMIT=40] -->
<string name="workspace_cling_longpress_title">Wallpapers, widgets, & settings</string>
<!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
<string name="workspace_cling_longpress_description">Touch & hold background to customize</string>
<!-- The description of the button to dismiss the cling [CHAR_LIMIT=30] -->
<string name="workspace_cling_longpress_dismiss">GOT IT</string>
- <!-- The title text for the Folder cling [CHAR_LIMIT=30] -->
- <string name="folder_cling_title">Here\'s a folder</string>
- <!-- The description of how to create a folder [CHAR_LIMIT=70] -->
- <string name="folder_cling_create_folder">To create one like this, touch & hold an app, then move it over another.</string>
<!-- The text on the button to dismiss a cling [CHAR_LIMIT=30] -->
<string name="cling_dismiss">OK</string>
- <!-- Error message on dummy custom cling layout [DO NOT TRANSLATE] -->
- <string name="dummy_custom_cling_error_message">Error: custom workspace layout passed in but custom cling was not overwritten</string>
<!-- Folder accessibility -->
<!-- The format string for when a folder is opened, speaks the dimensions -->
@@ -309,10 +200,13 @@
<!-- Strings for accessibility actions -->
<!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
- <string name="action_add_to_workspace">Add to workspace</string>
+ <string name="action_add_to_workspace">Add to home screen</string>
+
+ <!-- Accessibility action to move item to the current location. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
+ <string name="action_move_here">Move here</string>
<!-- Accessibility confirmation for item added to workspace [DO NOT TRANSLATE] -->
- <string name="item_added_to_workspace">Item added to workspace</string>
+ <string name="item_added_to_workspace">Item added to home screen</string>
<!-- Accessibility confirmation for item removed [DO NOT TRANSLATE] -->
<string name="item_removed">Item removed</string>
@@ -321,7 +215,13 @@
<string name="action_move">Move Item</string>
<!-- Accessibility description to move item to empty cell. [DO NOT TRANSLATE] -->
- <string name="move_to_empty_cell">Move to empty cell <xliff:g id="number" example="1">%1$s</xliff:g>, <xliff:g id="number" example="1">%2$s</xliff:g></string>
+ <string name="move_to_empty_cell">Move to row <xliff:g id="number" example="1">%1$s</xliff:g> column <xliff:g id="number" example="1">%2$s</xliff:g></string>
+
+ <!-- Accessibility description to move item inside a folder. [DO NOT TRANSLATE] -->
+ <string name="move_to_position">Move to position <xliff:g id="number" example="1">%1$s</xliff:g></string>
+
+ <!-- Accessibility description to move item to the hotseat. [DO NOT TRANSLATE] -->
+ <string name="move_to_hotseat_position">Move to favorites position <xliff:g id="number" example="1">%1$s</xliff:g></string>
<!-- Accessibility confirmation for item move [DO NOT TRANSLATE]-->
<string name="item_moved">Item moved</string>
@@ -329,6 +229,9 @@
<!-- Accessibility description to move item into an existing folder. [DO NOT TRANSLATE]-->
<string name="add_to_folder">Add to folder: <xliff:g id="name" example="Games">%1$s</xliff:g></string>
+ <!-- Accessibility description to move item into an existing folder containing an app. [DO NOT TRANSLATE]-->
+ <string name="add_to_folder_with_app">Add to folder with <xliff:g id="name" example="Messenger">%1$s</xliff:g></string>
+
<!-- Accessibility confirmation for item added to folder [DO NOT TRANSLATE] -->
<string name="added_to_folder">Item added to folder</string>
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java
index 2ee5a62..c7ee2e9 100644
--- a/src/com/android/launcher3/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/AlphabeticalAppsList.java
@@ -254,7 +254,7 @@
int length = apps.size();
for (int i = 0; i < length; ++i) {
AppInfo info = apps.get(i);
- if (info.user.equals(info.user)
+ if (info.user.equals(targetInfo.user)
&& info.intent.getComponent().equals(targetComponent)) {
return i;
}
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index fb49df5..683c511 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -16,14 +16,16 @@
package com.android.launcher3;
+import android.animation.ObjectAnimator;
+import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
+import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
@@ -42,8 +44,6 @@
private static int DRAG_VIEW_DROP_DURATION = 285;
- protected final int mTransitionDuration;
-
protected Launcher mLauncher;
private int mBottomDragPadding;
protected TextView mText;
@@ -58,16 +58,15 @@
protected ColorStateList mOriginalTextColor;
protected TransitionDrawable mDrawable;
+ private ObjectAnimator mCurrentColorAnim;
+
public ButtonDropTarget(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ButtonDropTarget(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
- Resources r = getResources();
- mTransitionDuration = r.getInteger(R.integer.config_dropTargetBgTransitionDuration);
- mBottomDragPadding = r.getDimensionPixelSize(R.dimen.drop_target_drag_padding);
+ mBottomDragPadding = getResources().getDimensionPixelSize(R.dimen.drop_target_drag_padding);
}
@Override
@@ -118,13 +117,18 @@
}
@Override
- public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { }
+ public void onFlingToDelete(DragObject d, PointF vec) { }
@Override
public final void onDragEnter(DragObject d) {
d.dragView.setColor(mHoverColor);
- mDrawable.startTransition(mTransitionDuration);
- setTextColor(mHoverColor);
+ if (Utilities.isLmpOrAbove()) {
+ mDrawable.startTransition(DragView.COLOR_CHANGE_DURATION);
+ animateTextColor(mHoverColor);
+ } else {
+ mDrawable.startTransition(0);
+ setTextColor(mHoverColor);
+ }
}
@Override
@@ -133,8 +137,23 @@
}
protected void resetHoverColor() {
- mDrawable.resetTransition();
- setTextColor(mOriginalTextColor);
+ if (Utilities.isLmpOrAbove()) {
+ mDrawable.reverseTransition(DragView.COLOR_CHANGE_DURATION);
+ animateTextColor(mOriginalTextColor.getDefaultColor());
+ } else {
+ mDrawable.resetTransition();
+ setTextColor(mOriginalTextColor);
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void animateTextColor(int targetColor) {
+ if (mCurrentColorAnim != null) {
+ mCurrentColorAnim.cancel();
+ }
+ mCurrentColorAnim = ObjectAnimator.ofArgb(this, "textColor", targetColor);
+ mCurrentColorAnim.setDuration(DragView.COLOR_CHANGE_DURATION);
+ mCurrentColorAnim.start();
}
@Override
@@ -152,6 +171,10 @@
public final void onDragStart(DragSource source, Object info, int dragAction) {
mActive = supportsDrop(source, info);
mDrawable.resetTransition();
+ if (mCurrentColorAnim != null) {
+ mCurrentColorAnim.cancel();
+ mCurrentColorAnim = null;
+ }
setTextColor(mOriginalTextColor);
((ViewGroup) getParent()).setVisibility(mActive ? View.VISIBLE : View.GONE);
}
@@ -203,6 +226,9 @@
DragLayer.ANIMATION_END_DISAPPEAR, null);
}
+ @Override
+ public void prepareAccessibilityDrop() { }
+
@Thunk abstract void completeDrop(DragObject d);
@Override
@@ -271,4 +297,8 @@
LauncherAppState.getInstance().getAccessibilityDelegate()
.handleAccessibleDrop(this, null, getAccessibilityDropConfirmation());
}
+
+ public int getTextColor() {
+ return getTextColors().getDefaultColor();
+ }
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index f08f25f..65c6702 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -35,11 +35,8 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
-import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -48,12 +45,12 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LayoutAnimationController;
import com.android.launcher3.FolderIcon.FolderRingAnimator;
-import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
+import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
+import com.android.launcher3.accessibility.FolderAccessibilityHelper;
+import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -62,10 +59,12 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.List;
import java.util.Stack;
public class CellLayout extends ViewGroup {
+ public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
+ public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
+
static final String TAG = "CellLayout";
private Launcher mLauncher;
@@ -121,7 +120,6 @@
// If we're actively dragging something over this screen, mIsDragOverlapping is true
private boolean mIsDragOverlapping = false;
- boolean mUseActiveGlowBackground = false;
// These arrays are used to implement the drag visualization on x-large screens.
// They are used as circular arrays, indexed by mDragOutlineCurrent.
@@ -181,12 +179,8 @@
private final static Paint sPaint = new Paint();
// Related to accessible drag and drop
- DragAndDropAccessibilityDelegate mTouchHelper = new DragAndDropAccessibilityDelegate(this);
+ private DragAndDropAccessibilityDelegate mTouchHelper;
private boolean mUseTouchHelper = false;
- OnClickListener mOldClickListener = null;
- OnClickListener mOldWorkspaceListener = null;
- @Thunk int mDownX = 0;
- @Thunk int mDownY = 0;
public CellLayout(Context context) {
this(context, null);
@@ -314,7 +308,7 @@
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public void enableAccessibleDrag(boolean enable) {
+ public void enableAccessibleDrag(boolean enable, int dragType) {
mUseTouchHelper = enable;
if (!enable) {
ViewCompat.setAccessibilityDelegate(this, null);
@@ -322,6 +316,13 @@
getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
setOnClickListener(mLauncher);
} else {
+ if (dragType == WORKSPACE_ACCESSIBILITY_DRAG &&
+ !(mTouchHelper instanceof WorkspaceAccessibilityHelper)) {
+ mTouchHelper = new WorkspaceAccessibilityHelper(this);
+ } else if (dragType == FOLDER_ACCESSIBILITY_DRAG &&
+ !(mTouchHelper instanceof FolderAccessibilityHelper)) {
+ mTouchHelper = new FolderAccessibilityHelper(this);
+ }
ViewCompat.setAccessibilityDelegate(this, mTouchHelper);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -345,15 +346,6 @@
}
@Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- mDownX = (int) event.getX();
- mDownY = (int) event.getY();
- }
- return super.dispatchTouchEvent(event);
- }
-
- @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mUseTouchHelper ||
(mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) {
@@ -362,252 +354,6 @@
return false;
}
- class DragAndDropAccessibilityDelegate extends ExploreByTouchHelper implements OnClickListener {
- private final Rect mTempRect = new Rect();
-
- public DragAndDropAccessibilityDelegate(View forView) {
- super(forView);
- }
-
- private int getViewIdAt(float x, float y) {
- if (x < 0 || y < 0 || x > getMeasuredWidth() || y > getMeasuredHeight()) {
- return ExploreByTouchHelper.INVALID_ID;
- }
-
- // Map coords to cell
- int cellX = (int) Math.floor(x / (mCellWidth + mWidthGap));
- int cellY = (int) Math.floor(y / (mCellHeight + mHeightGap));
-
- // Map cell to id
- int id = cellX * mCountY + cellY;
- return id;
- }
-
- @Override
- protected int getVirtualViewAt(float x, float y) {
- return nearestDropLocation(getViewIdAt(x, y));
- }
-
- protected int nearestDropLocation(int id) {
- int count = mCountX * mCountY;
- for (int delta = 0; delta < count; delta++) {
- if (id + delta <= (count - 1)) {
- int target = intersectsValidDropTarget(id + delta);
- if (target >= 0) {
- return target;
- }
- } else if (id - delta >= 0) {
- int target = intersectsValidDropTarget(id - delta);
- if (target >= 0) {
- return target;
- }
- }
- }
- return ExploreByTouchHelper.INVALID_ID;
- }
-
- /**
- * Find the virtual view id corresponding to the top left corner of any drop region by which
- * the passed id is contained. For an icon, this is simply
- *
- * @param id the id we're interested examining (ie. does it fit there?)
- * @return the view id of the top left corner of a valid drop region or -1 if there is no
- * such valid region. For the icon, this can just be -1 or id.
- */
- protected int intersectsValidDropTarget(int id) {
- LauncherAccessibilityDelegate delegate =
- LauncherAppState.getInstance().getAccessibilityDelegate();
- if (delegate == null) {
- return -1;
- }
-
- int y = id % mCountY;
- int x = id / mCountY;
- LauncherAccessibilityDelegate.DragInfo dragInfo = delegate.getDragInfo();
-
- if (dragInfo.dragType == DragType.WIDGET) {
- // For a widget, every cell must be vacant. In addition, we will return any valid
- // drop target by which the passed id is contained.
- boolean fits = false;
-
- // These represent the amount that we can back off if we hit a problem. They
- // get consumed as we move up and to the right, trying new regions.
- int spanX = dragInfo.info.spanX;
- int spanY = dragInfo.info.spanY;
-
- for (int m = 0; m < spanX; m++) {
- for (int n = 0; n < spanY; n++) {
-
- fits = true;
- int x0 = x - m;
- int y0 = y - n;
-
- if (x0 < 0 || y0 < 0) continue;
-
- for (int i = x0; i < x0 + spanX; i++) {
- if (!fits) break;
- for (int j = y0; j < y0 + spanY; j++) {
- if (i >= mCountX || j >= mCountY || mOccupied[i][j]) {
- fits = false;
- break;
- }
- }
- }
- if (fits) {
- return x0 * mCountY + y0;
- }
- }
- }
- return -1;
- } else {
- // For an icon, we simply check the view directly below
- View child = getChildAt(x, y);
- if (child == null || child == dragInfo.item) {
- // Empty cell. Good for an icon or folder.
- return id;
- } else if (dragInfo.dragType != DragType.FOLDER) {
- // For icons, we can consider cells that have another icon or a folder.
- ItemInfo info = (ItemInfo) child.getTag();
- if (info instanceof AppInfo || info instanceof FolderInfo ||
- info instanceof ShortcutInfo) {
- return id;
- }
- }
- return -1;
- }
- }
-
- @Override
- protected void getVisibleVirtualViews(List<Integer> virtualViews) {
- // We create a virtual view for each cell of the grid
- // The cell ids correspond to cells in reading order.
- int nCells = mCountX * mCountY;
-
- for (int i = 0; i < nCells; i++) {
- if (intersectsValidDropTarget(i) >= 0) {
- virtualViews.add(i);
- }
- }
- }
-
- @Override
- protected boolean onPerformActionForVirtualView(int viewId, int action, Bundle args) {
- LauncherAccessibilityDelegate delegate =
- LauncherAppState.getInstance().getAccessibilityDelegate();
- if (delegate == null) {
- return false;
- }
-
- if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
- String confirmation = getConfirmationForIconDrop(viewId);
- delegate.handleAccessibleDrop(CellLayout.this, getItemBounds(viewId), confirmation);
- return true;
- }
- return false;
- }
-
- @Override
- public void onClick(View arg0) {
- LauncherAccessibilityDelegate delegate =
- LauncherAppState.getInstance().getAccessibilityDelegate();
- if (delegate == null) {
- return;
- }
-
- int viewId = getViewIdAt(mDownX, mDownY);
-
- String confirmation = getConfirmationForIconDrop(viewId);
- delegate.handleAccessibleDrop(CellLayout.this, getItemBounds(viewId), confirmation);
- }
-
- @Override
- protected void onPopulateEventForVirtualView(int id, AccessibilityEvent event) {
- if (id == ExploreByTouchHelper.INVALID_ID) {
- throw new IllegalArgumentException("Invalid virtual view id");
- }
- // We're required to set something here.
- event.setContentDescription("");
- }
-
- @Override
- protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
- if (id == ExploreByTouchHelper.INVALID_ID) {
- throw new IllegalArgumentException("Invalid virtual view id");
- }
-
- node.setContentDescription(getLocationDescriptionForIconDrop(id));
- node.setBoundsInParent(getItemBounds(id));
-
- node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
- node.setClickable(true);
- node.setFocusable(true);
- }
-
- private String getLocationDescriptionForIconDrop(int id) {
- LauncherAccessibilityDelegate delegate =
- LauncherAppState.getInstance().getAccessibilityDelegate();
- if (delegate == null) {
- return "";
- }
-
- int y = id % mCountY;
- int x = id / mCountY;
- LauncherAccessibilityDelegate.DragInfo dragInfo = delegate.getDragInfo();
-
- Resources res = getContext().getResources();
- View child = getChildAt(x, y);
- if (child == null || child == dragInfo.item) {
- return res.getString(R.string.move_to_empty_cell, x + 1, y + 1);
- } else {
- ItemInfo info = (ItemInfo) child.getTag();
- if (info instanceof AppInfo || info instanceof ShortcutInfo) {
- return res.getString(R.string.create_folder_with, info.title);
- } else if (info instanceof FolderInfo) {
- return res.getString(R.string.add_to_folder, info.title);
- }
- }
- return "";
- }
-
- private String getConfirmationForIconDrop(int id) {
- LauncherAccessibilityDelegate delegate =
- LauncherAppState.getInstance().getAccessibilityDelegate();
- if (delegate == null) {
- return "";
- }
-
- int y = id % mCountY;
- int x = id / mCountY;
- LauncherAccessibilityDelegate.DragInfo dragInfo = delegate.getDragInfo();
-
- Resources res = getContext().getResources();
- View child = getChildAt(x, y);
- if (child == null || child == dragInfo.item) {
- return res.getString(R.string.item_moved);
- } else {
- ItemInfo info = (ItemInfo) child.getTag();
- if (info instanceof AppInfo || info instanceof ShortcutInfo) {
- return res.getString(R.string.folder_created);
-
- } else if (info instanceof FolderInfo) {
- return res.getString(R.string.added_to_folder);
- }
- }
- return "";
- }
-
- private Rect getItemBounds(int id) {
- int cellY = id % mCountY;
- int cellX = id / mCountY;
- int x = getPaddingLeft() + (int) (cellX * (mCellWidth + mWidthGap));
- int y = getPaddingTop() + (int) (cellY * (mCellHeight + mHeightGap));
-
- Rect bounds = mTempRect;
- bounds.set(x, y, x + mCellWidth, y + mCellHeight);
- return bounds;
- }
- }
-
public void enableHardwareLayer(boolean hasLayer) {
mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint);
}
@@ -684,10 +430,6 @@
}
}
- void setUseActiveGlowBackground(boolean use) {
- mUseActiveGlowBackground = use;
- }
-
void disableBackground() {
mDrawBackground = false;
}
@@ -703,7 +445,6 @@
void setIsDragOverlapping(boolean isDragOverlapping) {
if (mIsDragOverlapping != isDragOverlapping) {
mIsDragOverlapping = isDragOverlapping;
- setUseActiveGlowBackground(mIsDragOverlapping);
invalidate();
}
}
@@ -722,7 +463,7 @@
if (mDrawBackground && mBackgroundAlpha > 0.0f) {
Drawable bg;
- if (mUseActiveGlowBackground) {
+ if (mIsDragOverlapping) {
// In the mini case, we draw the active_glow bg *over* the active background
bg = mActiveGlowBackground;
} else {
@@ -905,8 +646,12 @@
mShortcutsAndWidgets.setIsHotseat(isHotseat);
}
+ public boolean isHotseat() {
+ return mIsHotseat;
+ }
+
public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
- boolean markCells, boolean inLayout) {
+ boolean markCells) {
final LayoutParams lp = params;
// Hotseat icons - remove text
@@ -927,7 +672,7 @@
if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
child.setId(childId);
- mShortcutsAndWidgets.addView(child, index, lp, inLayout);
+ mShortcutsAndWidgets.addView(child, index, lp);
if (markCells) markCellsAsOccupiedForView(child);
@@ -936,11 +681,6 @@
return false;
}
- public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
- boolean markCells) {
- return addViewToCellLayout(child, index, childId, params, markCells, false);
- }
-
@Override
public void removeAllViews() {
clearOccupiedCells();
@@ -955,10 +695,6 @@
}
}
- public void removeViewWithoutMarkingCells(View view) {
- mShortcutsAndWidgets.removeView(view);
- }
-
@Override
public void removeView(View view) {
markCellsAsUnoccupiedForView(view);
@@ -999,7 +735,7 @@
* @param y Y coordinate of the point
* @param result Array of 2 ints to hold the x and y coordinate of the cell
*/
- void pointToCellExact(int x, int y, int[] result) {
+ public void pointToCellExact(int x, int y, int[] result) {
final int hStartPadding = getPaddingLeft();
final int vStartPadding = getPaddingTop();
@@ -1088,9 +824,7 @@
public float getDistanceFromCell(float x, float y, int[] cell) {
cellToCenterPoint(cell[0], cell[1], mTmpPoint);
- float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
- Math.pow(y - mTmpPoint[1], 2));
- return distance;
+ return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]);
}
int getCellWidth() {
@@ -1109,28 +843,6 @@
return mHeightGap;
}
- Rect getContentRect(Rect r) {
- if (r == null) {
- r = new Rect();
- }
- int left = getPaddingLeft();
- int top = getPaddingTop();
- int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
- int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
- r.set(left, top, right, bottom);
- return r;
- }
-
- /** Return a rect that has the cellWidth/cellHeight (left, top), and
- * widthGap/heightGap (right, bottom) */
- static void getMetrics(Rect metrics, int paddedMeasureWidth,
- int paddedMeasureHeight, int countX, int countY) {
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- metrics.set(grid.calculateCellWidth(paddedMeasureWidth, countX),
- grid.calculateCellHeight(paddedMeasureHeight, countY), 0, 0);
- }
-
public void setFixedSize(int width, int height) {
mFixedWidth = width;
mFixedHeight = height;
@@ -1246,7 +958,6 @@
}
public void setBackgroundAlphaMultiplier(float multiplier) {
-
if (mBackgroundAlphaMultiplier != multiplier) {
mBackgroundAlphaMultiplier = multiplier;
invalidate();
@@ -1360,36 +1071,6 @@
return false;
}
- /**
- * Estimate where the top left cell of the dragged item will land if it is dropped.
- *
- * @param originX The X value of the top left corner of the item
- * @param originY The Y value of the top left corner of the item
- * @param spanX The number of horizontal cells that the item spans
- * @param spanY The number of vertical cells that the item spans
- * @param result The estimated drop cell X and Y.
- */
- void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
- final int countX = mCountX;
- final int countY = mCountY;
-
- // pointToCellRounded takes the top left of a cell but will pad that with
- // cellWidth/2 and cellHeight/2 when finding the matching cell
- pointToCellRounded(originX, originY, result);
-
- // If the item isn't fully on this screen, snap to the edges
- int rightOverhang = result[0] + spanX - countX;
- if (rightOverhang > 0) {
- result[0] -= rightOverhang; // Snap to right
- }
- result[0] = Math.max(0, result[0]); // Snap to left
- int bottomOverhang = result[1] + spanY - countY;
- if (bottomOverhang > 0) {
- result[1] -= bottomOverhang; // Snap to bottom
- }
- result[1] = Math.max(0, result[1]); // Snap to top
- }
-
void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
final int oldDragCellX = mDragCell[0];
@@ -1473,9 +1154,8 @@
* @return The X, Y cell of a vacant area that can contain this object,
* nearest the requested location.
*/
- int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
- int[] result) {
- return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
+ int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+ return findNearestVacantArea(pixelX, pixelY, spanX, spanY, spanX, spanY, result, null);
}
/**
@@ -1495,30 +1175,10 @@
*/
int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
int spanY, int[] result, int[] resultSpan) {
- return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
+ return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true,
result, resultSpan);
}
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreOccupied If true, the result can be an occupied cell
- * @param result Array in which to place the result, or null (in which case a new array will
- * be allocated)
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
- boolean ignoreOccupied, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY,
- spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
- }
-
private final Stack<Rect> mTempRectStack = new Stack<Rect>();
private void lazyInitTempRectStack() {
if (mTempRectStack.isEmpty()) {
@@ -1550,12 +1210,9 @@
* @return The X, Y cell of a vacant area that can contain this object,
* nearest the requested location.
*/
- int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
- View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
- boolean[][] occupied) {
+ private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
+ int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
lazyInitTempRectStack();
- // mark space take by ignoreView as available (method checks if ignoreView is null)
- markCellsAsUnoccupiedForView(ignoreView, occupied);
// For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
// to the center of the item, but we are searching based on the top-left cell, so
@@ -1586,7 +1243,7 @@
// First, let's see if this thing fits anywhere
for (int i = 0; i < minSpanX; i++) {
for (int j = 0; j < minSpanY; j++) {
- if (occupied[x + i][y + j]) {
+ if (mOccupied[x + i][y + j]) {
continue inner;
}
}
@@ -1603,7 +1260,7 @@
while (!(hitMaxX && hitMaxY)) {
if (incX && !hitMaxX) {
for (int j = 0; j < ySize; j++) {
- if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
+ if (x + xSize > countX -1 || mOccupied[x + xSize][y + j]) {
// We can't move out horizontally
hitMaxX = true;
}
@@ -1613,7 +1270,7 @@
}
} else if (!hitMaxY) {
for (int i = 0; i < xSize; i++) {
- if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
+ if (y + ySize > countY - 1 || mOccupied[x + i][y + ySize]) {
// We can't move out vertically
hitMaxY = true;
}
@@ -1646,8 +1303,7 @@
}
}
validRegions.push(currentRect);
- double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
- + Math.pow(cellXY[1] - pixelY, 2));
+ double distance = Math.hypot(cellXY[0] - pixelX, cellXY[1] - pixelY);
if ((distance <= bestDistance && !contained) ||
currentRect.contains(bestRect)) {
@@ -1662,8 +1318,6 @@
}
}
}
- // re-mark space taken by ignoreView as occupied
- markCellsAsOccupiedForView(ignoreView, occupied);
// Return -1, -1 if no suitable location found
if (bestDistance == Double.MAX_VALUE) {
@@ -1717,8 +1371,7 @@
}
}
- float distance = (float)
- Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
+ float distance = (float) Math.hypot(x - cellX, y - cellY);
int[] curDirection = mTmpPoint;
computeDirectionVector(x - cellX, y - cellY, curDirection);
// The direction score is just the dot product of the two candidate direction
@@ -2334,7 +1987,7 @@
}
}
- ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
+ private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
int spanX, int spanY, int[] direction, View dragView, boolean decX,
ItemConfiguration solution) {
// Copy the current state into the solution. This solution will be manipulated as necessary.
@@ -2623,7 +2276,7 @@
mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
}
- public void setUseTempCoords(boolean useTempCoords) {
+ private void setUseTempCoords(boolean useTempCoords) {
int childCount = mShortcutsAndWidgets.getChildCount();
for (int i = 0; i < childCount; i++) {
LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
@@ -2631,11 +2284,11 @@
}
}
- ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
+ private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
int spanX, int spanY, View dragView, ItemConfiguration solution) {
int[] result = new int[2];
int[] resultSpan = new int[2];
- findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
+ findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result,
resultSpan);
if (result[0] >= 0 && result[1] >= 0) {
copyCurrentStateToSolution(solution, false);
@@ -2952,45 +2605,6 @@
}
/**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreView Considers space occupied by this view as unoccupied
- * @param result Previously returned value to possibly recycle.
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestVacantArea(
- int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
- }
-
- /**
- * Find a vacant area that will fit the given bounds nearest the requested
- * cell location. Uses Euclidean distance to score multiple vacant areas.
- *
- * @param pixelX The X location at which you want to search for a vacant area.
- * @param pixelY The Y location at which you want to search for a vacant area.
- * @param minSpanX The minimum horizontal span required
- * @param minSpanY The minimum vertical span required
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreView Considers space occupied by this view as unoccupied
- * @param result Previously returned value to possibly recycle.
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
- int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
- return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
- result, resultSpan, mOccupied);
- }
-
- /**
* Find a starting cell position that will fit the given bounds nearest the requested
* cell location. Uses Euclidean distance to score multiple vacant areas.
*
@@ -3003,9 +2617,8 @@
* @return The X, Y cell of a vacant area that can contain this object,
* nearest the requested location.
*/
- int[] findNearestArea(
- int pixelX, int pixelY, int spanX, int spanY, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
+ int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+ return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null);
}
boolean existsEmptyCell() {
@@ -3026,103 +2639,32 @@
* @return True if a vacant cell of the specified dimension was found, false otherwise.
*/
public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
- return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
- }
-
- /**
- * Like above, but ignores any cells occupied by the item "ignoreView"
- *
- * @param cellXY The array that will contain the position of a vacant cell if such a cell
- * can be found.
- * @param spanX The horizontal span of the cell we want to find.
- * @param spanY The vertical span of the cell we want to find.
- * @param ignoreView The home screen item we should treat as not occupying any space
- * @return
- */
- boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
- return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
- ignoreView, mOccupied);
- }
-
- /**
- * Like above, but if intersectX and intersectY are not -1, then this method will try to
- * return coordinates for rectangles that contain the cell [intersectX, intersectY]
- *
- * @param spanX The horizontal span of the cell we want to find.
- * @param spanY The vertical span of the cell we want to find.
- * @param ignoreView The home screen item we should treat as not occupying any space
- * @param intersectX The X coordinate of the cell that we should try to overlap
- * @param intersectX The Y coordinate of the cell that we should try to overlap
- *
- * @return True if a vacant cell of the specified dimension was found, false otherwise.
- */
- boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
- int intersectX, int intersectY) {
- return findCellForSpanThatIntersectsIgnoring(
- cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
- }
-
- /**
- * The superset of the above two methods
- */
- boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
- int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
- // mark space take by ignoreView as available (method checks if ignoreView is null)
- markCellsAsUnoccupiedForView(ignoreView, occupied);
-
boolean foundCell = false;
- while (true) {
- int startX = 0;
- if (intersectX >= 0) {
- startX = Math.max(startX, intersectX - (spanX - 1));
- }
- int endX = mCountX - (spanX - 1);
- if (intersectX >= 0) {
- endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
- }
- int startY = 0;
- if (intersectY >= 0) {
- startY = Math.max(startY, intersectY - (spanY - 1));
- }
- int endY = mCountY - (spanY - 1);
- if (intersectY >= 0) {
- endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
- }
+ final int endX = mCountX - (spanX - 1);
+ final int endY = mCountY - (spanY - 1);
- for (int y = startY; y < endY && !foundCell; y++) {
- inner:
- for (int x = startX; x < endX; x++) {
- for (int i = 0; i < spanX; i++) {
- for (int j = 0; j < spanY; j++) {
- if (occupied[x + i][y + j]) {
- // small optimization: we can skip to after the column we just found
- // an occupied cell
- x += i;
- continue inner;
- }
+ for (int y = 0; y < endY && !foundCell; y++) {
+ inner:
+ for (int x = 0; x < endX; x++) {
+ for (int i = 0; i < spanX; i++) {
+ for (int j = 0; j < spanY; j++) {
+ if (mOccupied[x + i][y + j]) {
+ // small optimization: we can skip to after the column we just found
+ // an occupied cell
+ x += i;
+ continue inner;
}
}
- if (cellXY != null) {
- cellXY[0] = x;
- cellXY[1] = y;
- }
- foundCell = true;
- break;
}
- }
- if (intersectX == -1 && intersectY == -1) {
+ if (cellXY != null) {
+ cellXY[0] = x;
+ cellXY[1] = y;
+ }
+ foundCell = true;
break;
- } else {
- // if we failed to find anything, try again but without any requirements of
- // intersecting
- intersectX = -1;
- intersectY = -1;
- continue;
}
}
- // re-mark space taken by ignoreView as occupied
- markCellsAsOccupiedForView(ignoreView, occupied);
return foundCell;
}
@@ -3232,13 +2774,6 @@
return result;
}
- public int[] cellSpansToSize(int hSpans, int vSpans) {
- int[] size = new int[2];
- size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
- size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
- return size;
- }
-
/**
* Calculate the grid spans needed to fit given item
*/
@@ -3262,44 +2797,6 @@
info.spanY = spans[1];
}
- /**
- * Find the first vacant cell, if there is one.
- *
- * @param vacant Holds the x and y coordinate of the vacant cell
- * @param spanX Horizontal cell span.
- * @param spanY Vertical cell span.
- *
- * @return True if a vacant cell was found
- */
- public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
-
- return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
- }
-
- static boolean findVacantCell(int[] vacant, int spanX, int spanY,
- int xCount, int yCount, boolean[][] occupied) {
-
- for (int y = 0; (y + spanY) <= yCount; y++) {
- for (int x = 0; (x + spanX) <= xCount; x++) {
- boolean available = !occupied[x][y];
-out: for (int i = x; i < x + spanX; i++) {
- for (int j = y; j < y + spanY; j++) {
- available = available && !occupied[i][j];
- if (!available) break out;
- }
- }
-
- if (available) {
- vacant[0] = x;
- vacant[1] = y;
- return true;
- }
- }
- }
-
- return false;
- }
-
private void clearOccupiedCells() {
for (int x = 0; x < mCountX; x++) {
for (int y = 0; y < mCountY; y++) {
@@ -3308,27 +2805,16 @@
}
}
- public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
- markCellsAsUnoccupiedForView(view);
- markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
- }
-
public void markCellsAsOccupiedForView(View view) {
- markCellsAsOccupiedForView(view, mOccupied);
- }
- public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
if (view == null || view.getParent() != mShortcutsAndWidgets) return;
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
+ markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, true);
}
public void markCellsAsUnoccupiedForView(View view) {
- markCellsAsUnoccupiedForView(view, mOccupied);
- }
- public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
if (view == null || view.getParent() != mShortcutsAndWidgets) return;
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
+ markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, false);
}
private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
@@ -3374,17 +2860,6 @@
return new CellLayout.LayoutParams(p);
}
- public static class CellLayoutAnimationController extends LayoutAnimationController {
- public CellLayoutAnimationController(Animation animation, float delay) {
- super(animation, delay);
- }
-
- @Override
- protected long getDelayForView(View view) {
- return (int) (Math.random() * 150);
- }
- }
-
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
/**
* Horizontal location of the item in the grid.
@@ -3572,4 +3047,8 @@
public boolean lastDownOnOccupiedCell() {
return mLastDownOnOccupiedCell;
}
+
+ public boolean findVacantCell(int spanX, int spanY, int[] outXY) {
+ return Utilities.findVacantCell(outXY, spanX, spanY, mCountX, mCountY, mOccupied);
+ }
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index e741b97..08186f5 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -17,30 +17,18 @@
package com.android.launcher3;
import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.PointF;
-import android.graphics.Rect;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
+import com.android.launcher3.util.FlingAnimation;
import com.android.launcher3.util.Thunk;
-import com.android.launcher3.widget.WidgetsContainerView;
public class DeleteDropTarget extends ButtonDropTarget {
- private static int FLING_DELETE_ANIMATION_DURATION = 350;
- private static float FLING_TO_DELETE_FRICTION = 0.035f;
- private static int MODE_FLING_DELETE_TO_TRASH = 0;
- private static int MODE_FLING_DELETE_ALONG_VECTOR = 1;
-
- private final int mFlingDeleteMode = MODE_FLING_DELETE_ALONG_VECTOR;
-
public DeleteDropTarget(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -119,146 +107,19 @@
return true;
}
- /**
- * Creates an animation from the current drag view to the delete trash icon.
- */
- private AnimatorUpdateListener createFlingToTrashAnimatorListener(final DragLayer dragLayer,
- DragObject d, PointF vel, ViewConfiguration config) {
-
- int width = mDrawable.getIntrinsicWidth();
- int height = mDrawable.getIntrinsicHeight();
- final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
- width, height);
- final Rect from = new Rect();
- dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
- // Calculate how far along the velocity vector we should put the intermediate point on
- // the bezier curve
- float velocity = Math.abs(vel.length());
- float vp = Math.min(1f, velocity / (config.getScaledMaximumFlingVelocity() / 2f));
- int offsetY = (int) (-from.top * vp);
- int offsetX = (int) (offsetY / (vel.y / vel.x));
- final float y2 = from.top + offsetY; // intermediate t/l
- final float x2 = from.left + offsetX;
- final float x1 = from.left; // drag view t/l
- final float y1 = from.top;
- final float x3 = to.left; // delete target t/l
- final float y3 = to.top;
-
- final TimeInterpolator scaleAlphaInterpolator = new TimeInterpolator() {
- @Override
- public float getInterpolation(float t) {
- return t * t * t * t * t * t * t * t;
- }
- };
- return new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final DragView dragView = (DragView) dragLayer.getAnimatedView();
- float t = ((Float) animation.getAnimatedValue()).floatValue();
- float tp = scaleAlphaInterpolator.getInterpolation(t);
- float initialScale = dragView.getInitialScale();
- float finalAlpha = 0.5f;
- float scale = dragView.getScaleX();
- float x1o = ((1f - scale) * dragView.getMeasuredWidth()) / 2f;
- float y1o = ((1f - scale) * dragView.getMeasuredHeight()) / 2f;
- float x = (1f - t) * (1f - t) * (x1 - x1o) + 2 * (1f - t) * t * (x2 - x1o) +
- (t * t) * x3;
- float y = (1f - t) * (1f - t) * (y1 - y1o) + 2 * (1f - t) * t * (y2 - x1o) +
- (t * t) * y3;
-
- dragView.setTranslationX(x);
- dragView.setTranslationY(y);
- dragView.setScaleX(initialScale * (1f - tp));
- dragView.setScaleY(initialScale * (1f - tp));
- dragView.setAlpha(finalAlpha + (1f - finalAlpha) * (1f - tp));
- }
- };
- }
-
- /**
- * Creates an animation from the current drag view along its current velocity vector.
- * For this animation, the alpha runs for a fixed duration and we update the position
- * progressively.
- */
- private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
- private DragLayer mDragLayer;
- private PointF mVelocity;
- private Rect mFrom;
- private long mPrevTime;
- private boolean mHasOffsetForScale;
- private float mFriction;
-
- private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
-
- public FlingAlongVectorAnimatorUpdateListener(DragLayer dragLayer, PointF vel, Rect from,
- long startTime, float friction) {
- mDragLayer = dragLayer;
- mVelocity = vel;
- mFrom = from;
- mPrevTime = startTime;
- mFriction = 1f - (dragLayer.getResources().getDisplayMetrics().density * friction);
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final DragView dragView = (DragView) mDragLayer.getAnimatedView();
- float t = ((Float) animation.getAnimatedValue()).floatValue();
- long curTime = AnimationUtils.currentAnimationTimeMillis();
-
- if (!mHasOffsetForScale) {
- mHasOffsetForScale = true;
- float scale = dragView.getScaleX();
- float xOffset = ((scale - 1f) * dragView.getMeasuredWidth()) / 2f;
- float yOffset = ((scale - 1f) * dragView.getMeasuredHeight()) / 2f;
-
- mFrom.left += xOffset;
- mFrom.top += yOffset;
- }
-
- mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
- mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
-
- dragView.setTranslationX(mFrom.left);
- dragView.setTranslationY(mFrom.top);
- dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
-
- mVelocity.x *= mFriction;
- mVelocity.y *= mFriction;
- mPrevTime = curTime;
- }
- };
- private AnimatorUpdateListener createFlingAlongVectorAnimatorListener(final DragLayer dragLayer,
- DragObject d, PointF vel, final long startTime, final int duration,
- ViewConfiguration config) {
- final Rect from = new Rect();
- dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
- return new FlingAlongVectorAnimatorUpdateListener(dragLayer, vel, from, startTime,
- FLING_TO_DELETE_FRICTION);
- }
-
- public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) {
- final boolean isWidgets = d.dragSource instanceof WidgetsContainerView;
- final boolean isAllapps = d.dragSource instanceof AppsContainerView;
-
+ @Override
+ public void onFlingToDelete(final DragObject d, PointF vel) {
// Don't highlight the icon as it's animating
d.dragView.setColor(0);
d.dragView.updateInitialScaleToCurrentScale();
- // Don't highlight the target if we are flinging from AllApps
- if (isWidgets || isAllapps) {
- resetHoverColor();
- }
- if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
- // Defer animating out the drop target if we are animating to it
- mSearchDropTargetBar.deferOnDragEnd();
- mSearchDropTargetBar.finishAnimations();
- }
-
- final ViewConfiguration config = ViewConfiguration.get(mLauncher);
final DragLayer dragLayer = mLauncher.getDragLayer();
- final int duration = FLING_DELETE_ANIMATION_DURATION;
+ FlingAnimation fling = new FlingAnimation(d, vel,
+ getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
+ mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()),
+ dragLayer);
+
+ final int duration = fling.getDuration();
final long startTime = AnimationUtils.currentAnimationTimeMillis();
// NOTE: Because it takes time for the first frame of animation to actually be
@@ -282,27 +143,17 @@
return Math.min(1f, mOffset + t);
}
};
- AnimatorUpdateListener updateCb = null;
- if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
- updateCb = createFlingToTrashAnimatorListener(dragLayer, d, vel, config);
- } else if (mFlingDeleteMode == MODE_FLING_DELETE_ALONG_VECTOR) {
- updateCb = createFlingAlongVectorAnimatorListener(dragLayer, d, vel, startTime,
- duration, config);
- }
Runnable onAnimationEndRunnable = new Runnable() {
@Override
public void run() {
- // If we are dragging from AllApps, then we allow AppsCustomizePagedView to clean up
- // itself, otherwise, complete the drop to initiate the deletion process
- if (!isWidgets || !isAllapps) {
- mLauncher.exitSpringLoadedDragMode();
- completeDrop(d);
- }
+ mLauncher.exitSpringLoadedDragMode();
+ completeDrop(d);
mLauncher.getDragController().onDeferredEndFling(d);
}
};
- dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
+
+ dragLayer.animateView(d.dragView, fling, duration, tInterpolator, onAnimationEndRunnable,
DragLayer.ANIMATION_END_DISAPPEAR, null);
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 22fb6a0..deb8075 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -460,8 +460,7 @@
}
@Thunk float dist(PointF p0, PointF p1) {
- return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) +
- (p1.y-p0.y)*(p1.y-p0.y));
+ return (float) Math.hypot(p1.x - p0.x, p1.y - p0.y);
}
private float weight(PointF a, PointF b,
@@ -734,7 +733,6 @@
public void layout(Launcher launcher) {
FrameLayout.LayoutParams lp;
- Resources res = launcher.getResources();
boolean hasVerticalBarLayout = isVerticalBarLayout();
// Layout the search bar space
@@ -742,17 +740,22 @@
lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
if (hasVerticalBarLayout) {
// Vertical search bar space
- lp.gravity = Gravity.TOP | Gravity.LEFT;
+ lp.gravity = Gravity.LEFT;
lp.width = searchBarSpaceHeightPx;
- lp.height = LayoutParams.WRAP_CONTENT;
LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
targets.setOrientation(LinearLayout.VERTICAL);
+ FrameLayout.LayoutParams targetsLp = (FrameLayout.LayoutParams) targets.getLayoutParams();
+ targetsLp.gravity = Gravity.TOP;
+ targetsLp.height = LayoutParams.WRAP_CONTENT;
+
} else {
// Horizontal search bar space
- lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- lp.width = searchBarSpaceWidthPx;
+ lp.gravity = Gravity.TOP;
lp.height = searchBarSpaceHeightPx;
+
+ LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
+ targets.getLayoutParams().width = searchBarSpaceWidthPx;
}
searchBar.setLayoutParams(lp);
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index 1968868..5fea9d8 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -513,8 +513,7 @@
checkTouchMove(dropTarget);
// Check if we are hovering over the scroll areas
- mDistanceSinceScroll +=
- Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
+ mDistanceSinceScroll += Math.hypot(mLastTouch[0] - x, mLastTouch[1] - y);
mLastTouch[0] = x;
mLastTouch[1] = y;
checkScrollState(x, y);
@@ -659,6 +658,7 @@
mDragObject.y = coordinates[1];
checkTouchMove(dropTarget);
+ dropTarget.prepareAccessibilityDrop();
// Perform the drop
drop(location[0], location[1]);
endDrag();
@@ -710,8 +710,7 @@
mDragObject.dragComplete = true;
mFlingToDeleteDropTarget.onDragExit(mDragObject);
if (mFlingToDeleteDropTarget.acceptDrop(mDragObject)) {
- mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, mDragObject.x, mDragObject.y,
- vel);
+ mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, vel);
accepted = true;
}
mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject, true,
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index ab2e094..91f97fa 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -657,8 +657,7 @@
final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
// Calculate the duration of the animation based on the object's distance
- final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
- Math.pow(to.top - from.top, 2));
+ final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top);
final Resources res = getResources();
final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java
index b1a6266..a4b6704 100644
--- a/src/com/android/launcher3/DragView.java
+++ b/src/com/android/launcher3/DragView.java
@@ -16,22 +16,30 @@
package com.android.launcher3;
+import android.animation.FloatArrayEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
+import android.os.Build;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import com.android.launcher3.util.Thunk;
+import java.util.Arrays;
+
public class DragView extends View {
+ public static int COLOR_CHANGE_DURATION = 200;
+
@Thunk static float sDragAlpha = 1f;
private Bitmap mBitmap;
@@ -54,6 +62,9 @@
// size. This is ignored for non-icons.
private float mIntrinsicIconScale = 1f;
+ private float[] mCurrentFilter;
+ private ValueAnimator mFilterAnimator;
+
/**
* Construct the drag view.
* <p>
@@ -229,11 +240,50 @@
mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
}
if (color != 0) {
- mPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
+ ColorMatrix m1 = new ColorMatrix();
+ m1.setSaturation(0);
+
+ ColorMatrix m2 = new ColorMatrix();
+ m2.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
+ Color.blue(color) / 255f, Color.alpha(color) / 255f);
+ m1.postConcat(m2);
+
+ if (Utilities.isLmpOrAbove()) {
+ animateFilterTo(m1.getArray());
+ } else {
+ mPaint.setColorFilter(new ColorMatrixColorFilter(m1));
+ invalidate();
+ }
} else {
- mPaint.setColorFilter(null);
+ if (!Utilities.isLmpOrAbove() || mCurrentFilter == null) {
+ mPaint.setColorFilter(null);
+ invalidate();
+ } else {
+ animateFilterTo(new ColorMatrix().getArray());
+ }
}
- invalidate();
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void animateFilterTo(float[] targetFilter) {
+ float[] oldFilter = mCurrentFilter == null ? new ColorMatrix().getArray() : mCurrentFilter;
+ mCurrentFilter = Arrays.copyOf(oldFilter, oldFilter.length);
+
+ if (mFilterAnimator != null) {
+ mFilterAnimator.cancel();
+ }
+ mFilterAnimator = ValueAnimator.ofObject(new FloatArrayEvaluator(mCurrentFilter),
+ oldFilter, targetFilter);
+ mFilterAnimator.setDuration(COLOR_CHANGE_DURATION);
+ mFilterAnimator.addUpdateListener(new AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mPaint.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
+ invalidate();
+ }
+ });
+ mFilterAnimator.start();
}
public boolean hasDrawn() {
@@ -301,4 +351,3 @@
}
}
}
-
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index c5cca3b..a3828c1 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -29,7 +29,7 @@
public static final String TAG = "DropTarget";
- class DragObject {
+ public static class DragObject {
public int x = -1;
public int y = -1;
@@ -164,7 +164,7 @@
* of onDrop(). (This is only called on objects that are set as the DragController's
* fling-to-delete target.
*/
- void onFlingToDelete(DragObject dragObject, int x, int y, PointF vec);
+ void onFlingToDelete(DragObject dragObject, PointF vec);
/**
* Check if a drop action can occur at, or near, the requested location.
@@ -183,6 +183,8 @@
*/
boolean acceptDrop(DragObject dragObject);
+ void prepareAccessibilityDrop();
+
// These methods are implemented in Views
void getHitRectRelativeToDragLayer(Rect outRect);
void getLocationInDragLayer(int[] loc);
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index dff47c2..a282805 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -49,8 +49,10 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.launcher3.CellLayout.CellInfo;
import com.android.launcher3.DragController.DragListener;
import com.android.launcher3.FolderInfo.FolderListener;
+import com.android.launcher3.LauncherAccessibilityDelegate.AccessibilityDragSource;
import com.android.launcher3.UninstallDropTarget.UninstallSource;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.util.Thunk;
@@ -63,7 +65,7 @@
*/
public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
- View.OnFocusChangeListener, DragListener, UninstallSource {
+ View.OnFocusChangeListener, DragListener, UninstallSource, AccessibilityDragSource {
private static final String TAG = "Launcher.Folder";
/**
@@ -83,12 +85,6 @@
public static final int SCROLL_HINT_DURATION = DragController.SCROLL_DELAY;
/**
- * Time in milliseconds for which an icon sticks to the target position
- * in case of a sorted folder.
- */
- private static final int SORTED_STICKY_REORDER_DELAY = 1500;
-
- /**
* Fraction of icon width which behave as scroll region.
*/
private static final float ICON_OVERSCROLL_WIDTH_FACTOR = 0.45f;
@@ -243,7 +239,10 @@
public boolean onLongClick(View v) {
// Return if global dragging is not enabled
if (!mLauncher.isDraggingEnabled()) return true;
+ return beginDrag(v, false);
+ }
+ private boolean beginDrag(View v, boolean accessible) {
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
ShortcutInfo item = (ShortcutInfo) tag;
@@ -251,7 +250,7 @@
return false;
}
- mLauncher.getWorkspace().beginDragShared(v, new Point(), this, false);
+ mLauncher.getWorkspace().beginDragShared(v, new Point(), this, accessible);
mCurrentDragInfo = item;
mEmptyCellRank = item.rank;
@@ -265,6 +264,20 @@
return true;
}
+ @Override
+ public void startDrag(CellInfo cellInfo, boolean accessible) {
+ beginDrag(cellInfo.cell, accessible);
+ }
+
+ @Override
+ public void enableAccessibleDrag(boolean enable) {
+ mLauncher.getSearchBar().enableAccessibleDrag(enable);
+ for (int i = 0; i < mContent.getChildCount(); i++) {
+ mContent.getPageAt(i).enableAccessibleDrag(enable, CellLayout.FOLDER_ACCESSIBILITY_DRAG);
+ }
+ mLauncher.getWorkspace().setAddNewPageOnDrag(!enable);
+ }
+
public boolean isEditingName() {
return mIsEditingName;
}
@@ -417,7 +430,7 @@
if (!(getParent() instanceof DragLayer)) return;
mContent.completePendingPageChanges();
- if (!(mDragInProgress && mContent.mIsSorted)) {
+ if (!mDragInProgress) {
// Open on the first page.
mContent.snapToPageImmediately(0);
}
@@ -459,7 +472,7 @@
int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
- float radius = (float) Math.sqrt(rx * rx + ry * ry);
+ float radius = (float) Math.hypot(rx, ry);
AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
Animator reveal = LauncherAnimUtils.createCircularReveal(this, (int) getPivotX(),
(int) getPivotY(), 0, radius);
@@ -533,12 +546,6 @@
mIsExternalDrag = true;
mDragInProgress = true;
- if (mContent.mIsSorted) {
- mScrollPauseAlarm.setOnAlarmListener(null);
- mScrollPauseAlarm.cancelAlarm();
- mScrollPauseAlarm.setAlarm(SORTED_STICKY_REORDER_DELAY);
- }
-
// Since this folder opened by another controller, it might not get onDrop or
// onDropComplete. Perform cleanup once drag-n-drop ends.
mDragController.addDragListener(this);
@@ -697,9 +704,15 @@
if (mInfo.opened) {
mLauncher.closeFolder();
mRearrangeOnClose = true;
+ } else if (mState == STATE_ANIMATING) {
+ mRearrangeOnClose = true;
} else {
rearrangeChildren();
+ clearDragInfo();
}
+ }
+
+ private void clearDragInfo() {
mCurrentDragInfo = null;
mCurrentDragView = null;
mSuppressOnAdd = false;
@@ -723,6 +736,18 @@
}
}
+ /**
+ * When performing an accessibility drop, onDrop is sent immediately after onDragEnter. So we
+ * need to complete all transient states based on timers.
+ */
+ @Override
+ public void prepareAccessibilityDrop() {
+ if (mReorderAlarm.alarmPending()) {
+ mReorderAlarm.cancelAlarm();
+ mReorderAlarmListener.onAlarm(mReorderAlarm);
+ }
+ }
+
public void onDropCompleted(final View target, final DragObject d,
final boolean isFlingToDelete, final boolean success) {
if (mDeferDropAfterUninstall) {
@@ -816,7 +841,8 @@
return true;
}
- public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
+ @Override
+ public void onFlingToDelete(DragObject d, PointF vec) {
// Do nothing
}
@@ -1018,6 +1044,7 @@
}
}
mSuppressFolderDeletion = false;
+ clearDragInfo();
}
@Thunk void replaceFolderWithFinalItem() {
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 3f08f43..a07a3dc 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -20,23 +20,16 @@
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.OvershootInterpolator;
-import android.widget.Switch;
import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
import com.android.launcher3.PageIndicator.PageMarkerResources;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.util.Thunk;
-import java.text.Collator;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -47,17 +40,10 @@
private static final boolean ALLOW_FOLDER_SCROLL = true;
- // To enable this flag, user_folder.xml needs to be modified to add sort button.
- private static final boolean ALLOW_ITEM_SORTING = false;
-
private static final int REORDER_ANIMATION_DURATION = 230;
private static final int START_VIEW_REORDER_DELAY = 30;
private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
- private static final int SPAN_TO_PAGE_DURATION = 350;
- private static final int SORT_ANIM_HIDE_DURATION = 130;
- private static final int SORT_ANIM_SHOW_DURATION = 160;
-
/**
* Fraction of the width to scroll when showing the next page hint.
*/
@@ -87,13 +73,8 @@
private FocusIndicatorView mFocusIndicatorView;
private PagedFolderKeyEventListener mKeyListener;
- private View mSortButton;
- private Switch mSortSwitch;
private View mPageIndicator;
- private boolean mSortOperationPending;
- boolean mIsSorted;
-
public FolderPagedView(Context context, AttributeSet attrs) {
super(context, attrs);
LauncherAppState app = LauncherAppState.getInstance();
@@ -114,6 +95,7 @@
mIconCache = app.getIconCache();
rtlLayout = getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
public void setFolder(Folder folder) {
@@ -121,132 +103,6 @@
mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
mKeyListener = new PagedFolderKeyEventListener(folder);
mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
-
- if (ALLOW_ITEM_SORTING) {
- // Initialize {@link #mSortSwitch} and {@link #mSortButton}.
- }
- }
-
- /**
- * Called when sort button is clicked.
- */
- private void onSortClicked() {
- if (mSortOperationPending) {
- return;
- }
- if (mIsSorted) {
- setIsSorted(false, true);
- } else {
- mSortOperationPending = true;
- doSort();
- }
- }
-
- private void setIsSorted(boolean isSorted, boolean saveChanges) {
- mIsSorted = isSorted;
- if (ALLOW_ITEM_SORTING) {
- mSortSwitch.setChecked(isSorted);
- mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
- saveChanges ? mFolder.mLauncher : null);
- }
- }
-
- /**
- * Sorts the contents of the folder and animates the icons on the first page to reflect
- * the changes.
- * Steps:
- * 1. Scroll to first page
- * 2. Sort all icons in one go
- * 3. Re-apply the old IconInfos on the first page (so that there is no instant change)
- * 4. Animate each view individually to reflect the new icon.
- */
- private void doSort() {
- if (!mSortOperationPending) {
- return;
- }
- if (getNextPage() != 0) {
- snapToPage(0, SPAN_TO_PAGE_DURATION, new DecelerateInterpolator());
- return;
- }
-
- mSortOperationPending = false;
- ShortcutInfo[][] oldItems = new ShortcutInfo[mGridCountX][mGridCountY];
- CellLayout currentPage = getCurrentCellLayout();
- for (int x = 0; x < mGridCountX; x++) {
- for (int y = 0; y < mGridCountY; y++) {
- View v = currentPage.getChildAt(x, y);
- if (v != null) {
- oldItems[x][y] = (ShortcutInfo) v.getTag();
- }
- }
- }
-
- ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
- Collections.sort(views, new ViewComparator());
- arrangeChildren(views, views.size());
-
- int delay = 0;
- float delayAmount = START_VIEW_REORDER_DELAY;
- final Interpolator hideInterpolator = new DecelerateInterpolator(2);
- final Interpolator showInterpolator = new OvershootInterpolator(0.8f);
-
- currentPage = getCurrentCellLayout();
- for (int x = 0; x < mGridCountX; x++) {
- for (int y = 0; y < mGridCountY; y++) {
- final BubbleTextView v = (BubbleTextView) currentPage.getChildAt(x, y);
- if (v != null) {
- final ShortcutInfo info = (ShortcutInfo) v.getTag();
- final Runnable clearPending = new Runnable() {
-
- @Override
- public void run() {
- mPendingAnimations.remove(v);
- v.setScaleX(1);
- v.setScaleY(1);
- }
- };
- if (oldItems[x][y] == null) {
- v.setScaleX(0);
- v.setScaleY(0);
- v.animate().setDuration(SORT_ANIM_SHOW_DURATION)
- .setStartDelay(SORT_ANIM_HIDE_DURATION + delay)
- .scaleX(1).scaleY(1).setInterpolator(showInterpolator)
- .withEndAction(clearPending);
- mPendingAnimations.put(v, clearPending);
- } else {
- // Apply the old iconInfo so that there is no sudden change.
- v.applyFromShortcutInfo(oldItems[x][y], mIconCache, false);
- v.animate().setStartDelay(delay).setDuration(SORT_ANIM_HIDE_DURATION)
- .scaleX(0).scaleY(0)
- .setInterpolator(hideInterpolator)
- .withEndAction(new Runnable() {
-
- @Override
- public void run() {
- // Apply the new iconInfo as part of the animation.
- v.applyFromShortcutInfo(info, mIconCache, false);
- v.animate().scaleX(1).scaleY(1)
- .setDuration(SORT_ANIM_SHOW_DURATION).setStartDelay(0)
- .setInterpolator(showInterpolator)
- .withEndAction(clearPending);
- }
- });
- mPendingAnimations.put(v, new Runnable() {
-
- @Override
- public void run() {
- clearPending.run();
- v.applyFromShortcutInfo(info, mIconCache, false);
- }
- });
- }
- delay += delayAmount;
- delayAmount *= VIEW_REORDER_DELAY_FACTOR;
- }
- }
- }
-
- setIsSorted(true, true);
}
/**
@@ -295,7 +151,6 @@
* @return list of items that could not be bound, probably because we hit the max size limit.
*/
public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
- mIsSorted = ALLOW_ITEM_SORTING && mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
ArrayList<View> icons = new ArrayList<View>();
ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
@@ -317,20 +172,6 @@
public int allocateRankForNewItem(ShortcutInfo info) {
int rank = getItemCount();
ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
- if (ALLOW_ITEM_SORTING && mIsSorted) {
- View tmp = new View(getContext());
- tmp.setTag(info);
- int index = Collections.binarySearch(views, tmp, new ViewComparator());
- if (index < 0) {
- rank = -index - 1;
- } else {
- // Item with same name already exists.
- // We will just insert it before that item.
- rank = index;
- }
-
- }
-
views.add(rank, null);
arrangeChildren(views, views.size(), false);
setCurrentPage(rank / mMaxItemsPerPage);
@@ -397,6 +238,7 @@
CellLayout page = new CellLayout(getContext());
page.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
page.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
+ page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
page.setInvertIfRtl(true);
page.setGridSize(mGridCountX, mGridCountY);
@@ -447,10 +289,6 @@
int position = 0;
int newX, newY, rank;
- boolean isSorted = mIsSorted;
-
- ViewComparator comparator = new ViewComparator();
- View lastView = null;
rank = 0;
for (int i = 0; i < itemCount; i++) {
View v = list.size() > i ? list.get(i) : null;
@@ -465,10 +303,6 @@
}
if (v != null) {
- if (lastView != null) {
- isSorted &= comparator.compare(lastView, v) <= 0;
- }
-
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
newX = position % mGridCountX;
newY = position / mGridCountX;
@@ -488,7 +322,6 @@
v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
}
- lastView = v;
rank ++;
position++;
}
@@ -506,23 +339,10 @@
setEnableOverscroll(getPageCount() > 1);
// Update footer
- if (ALLOW_ITEM_SORTING) {
- setIsSorted(isSorted, saveChanges);
- if (getPageCount() > 1) {
- mPageIndicator.setVisibility(View.VISIBLE);
- mSortButton.setVisibility(View.VISIBLE);
- mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
- } else {
- mPageIndicator.setVisibility(View.GONE);
- mSortButton.setVisibility(View.GONE);
- mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
- }
- } else {
- int indicatorVisibility = mPageIndicator.getVisibility();
- mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
- if (indicatorVisibility != mPageIndicator.getVisibility()) {
- mFolder.updateFooterHeight();
- }
+ int indicatorVisibility = mPageIndicator.getVisibility();
+ mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
+ if (indicatorVisibility != mPageIndicator.getVisibility()) {
+ mFolder.updateFooterHeight();
}
}
@@ -559,7 +379,7 @@
public int findNearestArea(int pixelX, int pixelY) {
int pageIndex = getNextPage();
CellLayout page = getPageAt(pageIndex);
- page.findNearestArea(pixelX, pixelY, 1, 1, null, false, sTempPosArray);
+ page.findNearestArea(pixelX, pixelY, 1, 1, sTempPosArray);
if (mFolder.isLayoutRtl()) {
sTempPosArray[0] = page.getCountX() - sTempPosArray[0] - 1;
}
@@ -630,17 +450,6 @@
if (mFolder != null) {
mFolder.updateTextViewFocus();
}
- if (ALLOW_ITEM_SORTING && mSortOperationPending && getNextPage() == 0) {
- post(new Runnable() {
-
- @Override
- public void run() {
- if (mSortOperationPending) {
- doSort();
- }
- }
- });
- }
}
/**
@@ -829,14 +638,4 @@
}
}
}
-
- private static class ViewComparator implements Comparator<View> {
- private final Collator mCollator = Collator.getInstance();
-
- @Override
- public int compare(View lhs, View rhs) {
- return mCollator.compare( ((ShortcutInfo) lhs.getTag()).title.toString(),
- ((ShortcutInfo) rhs.getTag()).title.toString());
- }
- }
}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 27dda64..23bcc85 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -146,10 +146,13 @@
return;
}
- if (DBG) Log.d(TAG, "Got INSTALL_SHORTCUT: " + data.toUri(0));
PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
- info = convertToLauncherActivityIfPossible(info);
+ if (info.launchIntent == null || info.label == null) {
+ if (DBG) Log.e(TAG, "Invalid install shortcut intent");
+ return;
+ }
+ info = convertToLauncherActivityIfPossible(info);
queuePendingShortcutInfo(info, context);
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index a6752dd..4533089 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1688,9 +1688,6 @@
mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
| LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
- } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
- || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
- getModel().forceReload();
}
}
};
@@ -1704,8 +1701,6 @@
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
// For handling managed profiles
- filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
- filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
if (ENABLE_DEBUG_INTENTS) {
filter.addAction(DebugIntents.DELETE_DATABASE);
filter.addAction(DebugIntents.MIGRATE_DATABASE);
@@ -3591,9 +3586,9 @@
text.clear();
// Populate event with a fake title based on the current state.
if (mState == State.APPS) {
- text.add("Apps");
+ text.add(getString(R.string.all_apps_button_label));
} else if (mState == State.WIDGETS) {
- text.add("Widgets");
+ text.add(getString(R.string.widget_button_text));
} else {
text.add(getString(R.string.all_apps_home_button_label));
}
@@ -3629,14 +3624,13 @@
* in onResume.
*
* This needs to be called from incoming places where resources might have been loaded
- * while we are paused. That is becaues the Configuration might be wrong
- * when we're not running, and if it comes back to what it was when we
- * were paused, we are not restarted.
+ * while the activity is paused. That is because the Configuration (e.g., rotation) might be
+ * wrong when we're not running, and if the activity comes back to what the configuration was
+ * when we were paused, activity is not restarted.
*
* Implementation of the method from LauncherModel.Callbacks.
*
- * @return true if we are currently paused. The caller might be able to
- * skip some work in that case since we will come back again.
+ * @return {@code true} if we are currently paused. The caller might be able to skip some work
*/
private boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
if (mPaused) {
@@ -3747,19 +3741,6 @@
}
}
- @Override
- public void bindAddPendingItem(final PendingAddItemInfo info, final long container,
- final long screenId, final int[] cell, final int spanX, final int spanY) {
- showWorkspace(true, new Runnable() {
-
- @Override
- public void run() {
- mWorkspace.snapToPage(mWorkspace.getPageIndexForScreenId(screenId));
- addPendingItem(info, container, screenId, cell, spanX, spanY);
- }
- });
- }
-
private boolean shouldShowWeightWatcher() {
String spKey = LauncherAppState.getSharedPreferencesKey();
SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
@@ -4193,10 +4174,6 @@
if (mAppsView != null) {
mAppsView.setApps(apps);
}
- if (mWidgetsView != null) {
- mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false),
- getPackageManager());
- }
if (mLauncherCallbacks != null) {
mLauncherCallbacks.bindAllApplications(apps);
}
@@ -4332,26 +4309,23 @@
}
}
- /**
- * A number of packages were updated.
- */
@Thunk ArrayList<Object> mWidgetsAndShortcuts;
private Runnable mBindPackagesUpdatedRunnable = new Runnable() {
public void run() {
- bindPackagesUpdated(mWidgetsAndShortcuts);
- mWidgetsAndShortcuts = null;
+ bindAllPackages(mWidgetsAndShortcuts);
}
};
- public void bindPackagesUpdated(final ArrayList<Object> widgetsAndShortcuts) {
+ @Override
+ public void bindAllPackages(final ArrayList<Object> widgetsAndShortcuts) {
if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) {
mWidgetsAndShortcuts = widgetsAndShortcuts;
return;
}
- if (mWidgetsView != null) {
- mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false),
- getPackageManager());
+ if (mWidgetsView != null && widgetsAndShortcuts != null) {
+ mWidgetsView.addWidgets(widgetsAndShortcuts, getPackageManager());
+ mWidgetsAndShortcuts = null;
}
}
diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
index a60e160..a527db4 100644
--- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
@@ -5,13 +5,13 @@
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
+import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.View.AccessibilityDelegate;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import com.android.launcher3.LauncherModel.ScreenPosProvider;
import com.android.launcher3.util.Thunk;
import java.util.ArrayList;
@@ -19,30 +19,32 @@
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
- public static final int REMOVE = R.id.action_remove;
- public static final int INFO = R.id.action_info;
- public static final int UNINSTALL = R.id.action_uninstall;
- public static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
- public static final int MOVE = R.id.action_move;
+ private static final String TAG = "LauncherAccessibilityDelegate";
- enum DragType {
+ private static final int REMOVE = R.id.action_remove;
+ private static final int INFO = R.id.action_info;
+ private static final int UNINSTALL = R.id.action_uninstall;
+ private static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
+ private static final int MOVE = R.id.action_move;
+
+ public enum DragType {
ICON,
FOLDER,
WIDGET
}
public static class DragInfo {
- DragType dragType;
- ItemInfo info;
- View item;
+ public DragType dragType;
+ public ItemInfo info;
+ public View item;
}
- private DragInfo mDragInfo = null;
-
- private final SparseArray<AccessibilityAction> mActions =
- new SparseArray<AccessibilityAction>();
+ private final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
@Thunk final Launcher mLauncher;
+ private DragInfo mDragInfo = null;
+ private AccessibilityDragSource mDragSource = null;
+
public LauncherAccessibilityDelegate(Launcher launcher) {
mLauncher = launcher;
@@ -56,7 +58,6 @@
launcher.getText(R.string.action_add_to_workspace)));
mActions.put(MOVE, new AccessibilityAction(MOVE,
launcher.getText(R.string.action_move)));
-
}
@Override
@@ -93,7 +94,7 @@
return super.performAccessibilityAction(host, action, args);
}
- public boolean performAction(View host, ItemInfo item, int action) {
+ public boolean performAction(View host, final ItemInfo item, int action) {
if (action == REMOVE) {
if (DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host)) {
announceConfirmation(R.string.item_removed);
@@ -108,32 +109,32 @@
} else if (action == MOVE) {
beginAccessibleDrag(host, item);
} else if (action == ADD_TO_WORKSPACE) {
- final int preferredPage = mLauncher.getWorkspace().getCurrentPage();
- final ScreenPosProvider screenProvider = new ScreenPosProvider() {
+ final int[] coordinates = new int[2];
+ final long screenId = findSpaceOnWorkspace(item, coordinates);
+ mLauncher.showWorkspace(true, new Runnable() {
@Override
- public int getScreenIndex(ArrayList<Long> screenIDs) {
- return preferredPage;
- }
- };
- if (item instanceof AppInfo) {
- final ArrayList<ItemInfo> addShortcuts = new ArrayList<ItemInfo>();
- addShortcuts.add(((AppInfo) item).makeShortcut());
- mLauncher.showWorkspace(true, new Runnable() {
- @Override
- public void run() {
- mLauncher.getModel().addAndBindAddedWorkspaceItems(
- mLauncher, addShortcuts, screenProvider, 0, true);
- announceConfirmation(R.string.item_added_to_workspace);
+ public void run() {
+ if (item instanceof AppInfo) {
+ ShortcutInfo info = ((AppInfo) item).makeShortcut();
+ LauncherModel.addItemToDatabase(mLauncher, info,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP,
+ screenId, coordinates[0], coordinates[1]);
+
+ ArrayList<ItemInfo> itemList = new ArrayList<>();
+ itemList.add(info);
+ mLauncher.bindItems(itemList, 0, itemList.size(), true);
+ } else if (item instanceof PendingAddItemInfo) {
+ PendingAddItemInfo info = (PendingAddItemInfo) item;
+ Workspace workspace = mLauncher.getWorkspace();
+ workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
+ mLauncher.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+ screenId, coordinates, info.spanX, info.spanY);
}
- });
- return true;
- } else if (item instanceof PendingAddItemInfo) {
- mLauncher.getModel().addAndBindPendingItem(
- mLauncher, (PendingAddItemInfo) item, screenProvider, 0);
- announceConfirmation(R.string.item_added_to_workspace);
- return true;
- }
+ announceConfirmation(R.string.item_added_to_workspace);
+ }
+ });
+ return true;
}
return false;
}
@@ -197,10 +198,23 @@
Rect pos = new Rect();
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(item, pos);
-
mLauncher.getDragController().prepareAccessibleDrag(pos.centerX(), pos.centerY());
- mLauncher.getWorkspace().enableAccessibleDrag(true);
- mLauncher.getWorkspace().startDrag(cellInfo, true);
+
+ Workspace workspace = mLauncher.getWorkspace();
+
+ Folder folder = workspace.getOpenFolder();
+ if (folder != null) {
+ if (folder.getItemsInReadingOrder().contains(item)) {
+ mDragSource = folder;
+ } else {
+ mLauncher.closeFolder();
+ }
+ }
+ if (mDragSource == null) {
+ mDragSource = workspace;
+ }
+ mDragSource.enableAccessibleDrag(true);
+ mDragSource.startDrag(cellInfo, true);
}
public boolean onBackPressed() {
@@ -218,6 +232,52 @@
private void endAccessibleDrag() {
mDragInfo = null;
- mLauncher.getWorkspace().enableAccessibleDrag(false);
+ if (mDragSource != null) {
+ mDragSource.enableAccessibleDrag(false);
+ mDragSource = null;
+ }
+ }
+
+ public static interface AccessibilityDragSource {
+ void startDrag(CellLayout.CellInfo cellInfo, boolean accessible);
+
+ void enableAccessibleDrag(boolean enable);
+ }
+
+ /**
+ * Find empty space on the workspace and returns the screenId.
+ */
+ private long findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
+ Workspace workspace = mLauncher.getWorkspace();
+ ArrayList<Long> workspaceScreens = workspace.getScreenOrder();
+ long screenId;
+
+ // First check if there is space on the current screen.
+ int screenIndex = workspace.getCurrentPage();
+ screenId = workspaceScreens.get(screenIndex);
+ CellLayout layout = (CellLayout) workspace.getPageAt(screenIndex);
+
+ boolean found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+ screenIndex = workspace.hasCustomContent() ? 1 : 0;
+ while (!found && screenIndex < workspaceScreens.size()) {
+ screenId = workspaceScreens.get(screenIndex);
+ layout = (CellLayout) workspace.getPageAt(screenIndex);
+ found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+ screenIndex++;
+ }
+
+ if (found) {
+ return screenId;
+ }
+
+ workspace.addExtraEmptyScreen();
+ screenId = workspace.commitExtraEmptyScreen();
+ layout = workspace.getScreenWithId(screenId);
+ found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+
+ if (!found) {
+ Log.wtf(TAG, "Not enough space on an empty screen");
+ }
+ return screenId;
}
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 7f31e49..d51df32 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -112,6 +112,10 @@
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
+ // For handling managed profiles
+ filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
+ filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
+
sContext.registerReceiver(mModel, filter);
}
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 064f436..92bbb40 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -88,11 +88,6 @@
/** widgets contain previews, which are very large, dribble them out */
private static final int MAX_WIDGETS_PER_PASS = 5;
- private static final int IMAGE_COMPRESSION_QUALITY = 75;
-
- private static final Bitmap.CompressFormat IMAGE_FORMAT =
- android.graphics.Bitmap.CompressFormat.PNG;
-
private static final String[] FAVORITE_PROJECTION = {
Favorites._ID, // 0
Favorites.MODIFIED, // 1
@@ -969,10 +964,7 @@
private Resource packIcon(int dpi, Bitmap icon) {
Resource res = new Resource();
res.dpi = dpi;
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
- res.data = os.toByteArray();
- }
+ res.data = Utilities.flattenBitmap(icon);
return res;
}
@@ -990,20 +982,14 @@
widget.icon = new Resource();
Drawable fullResIcon = iconCache.getFullResIcon(provider.getPackageName(), info.icon);
Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext);
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
- widget.icon.data = os.toByteArray();
- widget.icon.dpi = dpi;
- }
+ widget.icon.data = Utilities.flattenBitmap(icon);
+ widget.icon.dpi = dpi;
}
if (info.previewImage != 0) {
widget.preview = new Resource();
Bitmap preview = previewLoader.generateWidgetPreview(info, previewWidth, null);
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- if (preview.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
- widget.preview.data = os.toByteArray();
- widget.preview.dpi = dpi;
- }
+ widget.preview.data = Utilities.flattenBitmap(preview);
+ widget.preview.dpi = dpi;
}
return widget;
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index d5dce51..7fdd523 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -35,7 +35,6 @@
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
@@ -198,23 +197,17 @@
public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
public void bindComponentsRemoved(ArrayList<String> packageNames,
ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);
- public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
+ public void bindAllPackages(ArrayList<Object> widgetsAndShortcuts);
public void bindSearchablesChanged();
public boolean isAllAppsButtonRank(int rank);
public void onPageBoundSynchronously(int page);
public void dumpLogsToLocalData();
- public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,
- int[] cell, int spanX, int spanY);
}
public interface ItemInfoFilter {
public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);
}
- public interface ScreenPosProvider {
- int getScreenIndex(ArrayList<Long> screenIDs);
- }
-
LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
Context context = app.getContext();
@@ -406,19 +399,7 @@
runOnWorkerThread(r);
}
- public void addAndBindAddedWorkspaceItems(final Context context,
- final ArrayList<ItemInfo> workspaceApps) {
- addAndBindAddedWorkspaceItems(context, workspaceApps,
- new ScreenPosProvider() {
-
- @Override
- public int getScreenIndex(ArrayList<Long> screenIDs) {
- return screenIDs.isEmpty() ? 0 : 1;
- }
- }, 1, false);
- }
-
- private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,
+ private static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> occupiedPos,
int[] xy, int spanX, int spanY) {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
@@ -426,15 +407,17 @@
final int yCount = (int) grid.numRows;
boolean[][] occupied = new boolean[xCount][yCount];
if (occupiedPos != null) {
- for (Rect r : occupiedPos) {
- for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {
- for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {
+ for (ItemInfo r : occupiedPos) {
+ int right = r.cellX + r.spanX;
+ int bottom = r.cellY + r.spanY;
+ for (int x = r.cellX; 0 <= x && x < right && x < xCount; x++) {
+ for (int y = r.cellY; 0 <= y && y < bottom && y < yCount; y++) {
occupied[x][y] = true;
}
}
}
}
- return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
+ return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
}
/**
@@ -443,53 +426,24 @@
*/
@Thunk static Pair<Long, int[]> findSpaceForItem(
Context context,
- ScreenPosProvider preferredScreen,
- int fallbackStartScreen,
ArrayList<Long> workspaceScreens,
ArrayList<Long> addedWorkspaceScreensFinal,
int spanX, int spanY) {
- // Load position of items which are on the desktop. We can't use sBgItemsIdMap because
- // loadWorkspace() may not have been called.
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] {
- LauncherSettings.Favorites.SCREEN,
- LauncherSettings.Favorites.CELLX,
- LauncherSettings.Favorites.CELLY,
- LauncherSettings.Favorites.SPANX,
- LauncherSettings.Favorites.SPANY,
- LauncherSettings.Favorites.CONTAINER
- },
- "container=?",
- new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },
- null);
+ LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();
- final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
- final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
- LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();
- try {
- while (c.moveToNext()) {
- Rect rect = new Rect();
- rect.left = c.getInt(cellXIndex);
- rect.top = c.getInt(cellYIndex);
- rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));
- rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));
-
- long screenId = c.getInt(screenIndex);
- ArrayList<Rect> items = screenItems.get(screenId);
- if (items == null) {
- items = new ArrayList<Rect>();
- screenItems.put(screenId, items);
+ // Use sBgItemsIdMap as all the items are already loaded.
+ // TODO: Throw exception is above condition is not met.
+ synchronized (sBgLock) {
+ for (ItemInfo info : sBgItemsIdMap) {
+ if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ ArrayList<ItemInfo> items = screenItems.get(info.screenId);
+ if (items == null) {
+ items = new ArrayList<>();
+ screenItems.put(info.screenId, items);
+ }
+ items.add(info);
}
- items.add(rect);
}
- } catch (Exception e) {
- screenItems.clear();
- } finally {
- c.close();
}
// Find appropriate space for the item.
@@ -499,7 +453,7 @@
int screenCount = workspaceScreens.size();
// First check the preferred screen.
- int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);
+ int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;
if (preferredScreenIndex < screenCount) {
screenId = workspaceScreens.get(preferredScreenIndex);
found = findNextAvailableIconSpaceInScreen(
@@ -507,8 +461,8 @@
}
if (!found) {
- // Search on any of the screens.
- for (int screen = fallbackStartScreen; screen < screenCount; screen++) {
+ // Search on any of the screens starting from the first screen.
+ for (int screen = 1; screen < screenCount; screen++) {
screenId = workspaceScreens.get(screen);
if (findNextAvailableIconSpaceInScreen(
screenItems.get(screenId), cordinates, spanX, spanY)) {
@@ -538,59 +492,9 @@
/**
* Adds the provided items to the workspace.
- * @param preferredScreen the screen where we should try to add the app first
- * @param fallbackStartScreen the screen to start search for empty space if
- * preferredScreen is not available.
- */
- public void addAndBindPendingItem(
- final Context context,
- final PendingAddItemInfo addInfo,
- final ScreenPosProvider preferredScreen,
- final int fallbackStartScreen) {
- final Callbacks callbacks = getCallback();
- // Process the newly added applications and add them to the database first
- Runnable r = new Runnable() {
- public void run() {
- final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
- ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
-
- // Find appropriate space for the item.
- Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,
- fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,
- addInfo.spanX,
- addInfo.spanY);
- final long screenId = coords.first;
- final int[] cordinates = coords.second;
-
- // Update the workspace screens
- updateWorkspaceScreenOrder(context, workspaceScreens);
- runOnMainThread(new Runnable() {
- public void run() {
- Callbacks cb = getCallback();
- if (callbacks == cb && cb != null) {
- cb.bindAddScreens(addedWorkspaceScreensFinal);
- cb.bindAddPendingItem(addInfo,
- LauncherSettings.Favorites.CONTAINER_DESKTOP,
- screenId, cordinates, addInfo.spanX, addInfo.spanY);
- }
- }
- });
- }
- };
- runOnWorkerThread(r);
- }
-
- /**
- * Adds the provided items to the workspace.
- * @param preferredScreen the screen where we should try to add the app first
- * @param fallbackStartScreen the screen to start search for empty space if
- * preferredScreen is not available.
*/
public void addAndBindAddedWorkspaceItems(final Context context,
- final ArrayList<ItemInfo> workspaceApps,
- final ScreenPosProvider preferredScreen,
- final int fallbackStartScreen,
- final boolean allowDuplicate) {
+ final ArrayList<ItemInfo> workspaceApps) {
final Callbacks callbacks = getCallback();
if (workspaceApps.isEmpty()) {
return;
@@ -607,7 +511,7 @@
ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
synchronized(sBgLock) {
for (ItemInfo item : workspaceApps) {
- if (!allowDuplicate && item instanceof ShortcutInfo) {
+ if (item instanceof ShortcutInfo) {
// Short-circuit this logic if the icon exists somewhere on the workspace
if (shortcutExists(context, item.getIntent(), item.user)) {
continue;
@@ -615,8 +519,8 @@
}
// Find appropriate space for the item.
- Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,
- fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,
+ Pair<Long, int[]> coords = findSpaceForItem(context,
+ workspaceScreens, addedWorkspaceScreensFinal,
1, 1);
long screenId = coords.first;
int[] cordinates = coords.second;
@@ -977,22 +881,22 @@
* TODO: Throw exception is above condition is not met.
*/
@Thunk static boolean shortcutExists(Context context, Intent intent, UserHandleCompat user) {
- final Intent intentWithPkg, intentWithoutPkg;
+ final String intentWithPkg, intentWithoutPkg;
final String packageName;
if (intent.getComponent() != null) {
// If component is not null, an intent with null package will produce
// the same result and should also be a match.
packageName = intent.getComponent().getPackageName();
if (intent.getPackage() != null) {
- intentWithPkg = intent;
- intentWithoutPkg = new Intent(intent).setPackage(null);
+ intentWithPkg = intent.toUri(0);
+ intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);
} else {
- intentWithPkg = new Intent(intent).setPackage(packageName);
- intentWithoutPkg = intent;
+ intentWithPkg = new Intent(intent).setPackage(packageName).toUri(0);
+ intentWithoutPkg = intent.toUri(0);
}
} else {
- intentWithPkg = intent;
- intentWithoutPkg = intent;
+ intentWithPkg = intent.toUri(0);
+ intentWithoutPkg = intent.toUri(0);
packageName = intent.getPackage();
}
@@ -1000,9 +904,11 @@
for (ItemInfo item : sBgItemsIdMap) {
if (item instanceof ShortcutInfo) {
ShortcutInfo info = (ShortcutInfo) item;
- if (intentWithPkg.equals(info.getIntent())
- || intentWithoutPkg.equals(info.getIntent())) {
- return true;
+ if (info.getIntent() != null && info.user.equals(user)) {
+ String s = info.getIntent().toUri(0);
+ if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {
+ return true;
+ }
}
}
}
@@ -1373,6 +1279,9 @@
if (callbacks != null) {
callbacks.bindSearchablesChanged();
}
+ } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
+ || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
+ forceReload();
}
}
@@ -1690,9 +1599,6 @@
if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
loadAndBindAllApps();
- // Remove entries for packages which changed while the launcher was dead.
- LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews();
-
// Restore the default thread priority after we are done loading items
synchronized (mLock) {
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
@@ -2961,6 +2867,7 @@
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindAllApplications(added);
+ loadAndBindWidgetsAndShortcuts(mContext,callbacks);
if (DEBUG_LOADERS) {
Log.d(TAG, "bound " + added.size() + " apps in "
+ (SystemClock.uptimeMillis() - bindTime) + "ms");
@@ -3376,29 +3283,33 @@
runOnWorkerThread(new Runnable(){
@Override
public void run() {
- final ArrayList<Object> list =
- getSortedWidgetsAndShortcuts(context, true /* refresh */);
+ final ArrayList<Object> list = getWidgetsAndShortcuts(context, true /* refresh */);
mHandler.post(new Runnable() {
@Override
public void run() {
Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
- callbacks.bindPackagesUpdated(list);
+ callbacks.bindAllPackages(list);
}
}
});
+ // update the Widget entries inside DB on the worker thread.
+ LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(list);
}
});
}
- // Returns a list of ResolveInfos/AppWidgetInfos in sorted order
- public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context, boolean refresh) {
+ /**
+ * Returns a list of ResolveInfos/AppWidgetInfos.
+ *
+ * @see #loadAndBindWidgetsAndShortcuts
+ */
+ private ArrayList<Object> getWidgetsAndShortcuts(Context context, boolean refresh) {
PackageManager packageManager = context.getPackageManager();
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));
Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));
- Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));
return widgetsAndShortcuts;
}
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 1effe1e..51f84bf 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -258,7 +258,7 @@
// Setup the reveal view animation
int width = revealView.getMeasuredWidth();
int height = revealView.getMeasuredHeight();
- float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+ float revealRadius = (float) Math.hypot(width / 2, height / 2);
revealView.setVisibility(View.VISIBLE);
revealView.setAlpha(0f);
revealView.setTranslationY(0f);
@@ -563,7 +563,7 @@
if (fromView.getVisibility() == View.VISIBLE) {
int width = revealView.getMeasuredWidth();
int height = revealView.getMeasuredHeight();
- float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+ float revealRadius = (float) Math.hypot(width / 2, height / 2);
revealView.setVisibility(View.VISIBLE);
revealView.setAlpha(1f);
revealView.setTranslationY(0);
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 15b6176..56c8b39 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -76,14 +76,6 @@
return null;
}
- public void addView(View child, int index, LayoutParams params, boolean inLayout) {
- if (!inLayout) {
- addView(child, index, params);
- } else {
- addViewInLayout(child, index, params, false);
- }
- }
-
@Override
protected void dispatchDraw(Canvas canvas) {
@SuppressWarnings("all") // suppress dead code warning
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 4c52d7e..c351135 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -26,7 +26,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
// Get the hover color
- mHoverColor = getResources().getColor(R.color.delete_target_hover_tint);
+ mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
setDrawable(R.drawable.uninstall_target_selector);
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 22677c8..2dbf078 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -583,4 +583,37 @@
return lhs.rank - rhs.rank;
}
};
+
+ /**
+ * Find the first vacant cell, if there is one.
+ *
+ * @param vacant Holds the x and y coordinate of the vacant cell
+ * @param spanX Horizontal cell span.
+ * @param spanY Vertical cell span.
+ *
+ * @return true if a vacant cell was found
+ */
+ public static boolean findVacantCell(int[] vacant, int spanX, int spanY,
+ int xCount, int yCount, boolean[][] occupied) {
+
+ for (int y = 0; (y + spanY) <= yCount; y++) {
+ for (int x = 0; (x + spanX) <= xCount; x++) {
+ boolean available = !occupied[x][y];
+ out: for (int i = x; i < x + spanX; i++) {
+ for (int j = y; j < y + spanY; j++) {
+ available = available && !occupied[i][j];
+ if (!available) break out;
+ }
+ }
+
+ if (available) {
+ vacant[0] = x;
+ vacant[1] = y;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 5c3ed92..93bfeaf 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -24,6 +24,7 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
+import android.os.Process;
import android.util.Log;
import android.util.LongSparseArray;
@@ -34,7 +35,9 @@
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.WidgetCell;
-import java.lang.ref.WeakReference;
+import junit.framework.Assert;
+
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -51,8 +54,13 @@
private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f;
private final HashMap<String, long[]> mPackageVersions = new HashMap<>();
- private final HashMap<WidgetCacheKey, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>();
- private Set<Bitmap> mUnusedBitmaps = Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
+
+ /**
+ * Weak reference objects, do not prevent their referents from being made finalizable,
+ * finalized, and then reclaimed.
+ */
+ private Set<Bitmap> mUnusedBitmaps =
+ Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
private final Context mContext;
private final IconCache mIconCache;
@@ -84,18 +92,9 @@
String size = previewWidth + "x" + previewHeight;
WidgetCacheKey key = getObjectKey(o, size);
- // Check if we have the preview loaded or not.
- synchronized (mLoadedPreviews) {
- WeakReference<Bitmap> ref = mLoadedPreviews.get(key);
- if (ref != null && ref.get() != null) {
- immediateResult[0] = ref.get();
- return new PreviewLoadRequest(null, key);
- }
- }
-
PreviewLoadTask task = new PreviewLoadTask(key, o, previewWidth, previewHeight, caller);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- return new PreviewLoadRequest(task, key);
+ return new PreviewLoadRequest(task);
}
/**
@@ -192,22 +191,6 @@
mPackageVersions.remove(packageName);
}
- synchronized (mLoadedPreviews) {
- Set<WidgetCacheKey> keysToRemove = new HashSet<>();
- for (WidgetCacheKey key : mLoadedPreviews.keySet()) {
- if (key.componentName.getPackageName().equals(packageName) && key.user.equals(user)) {
- keysToRemove.add(key);
- }
- }
-
- for (WidgetCacheKey key : keysToRemove) {
- WeakReference<Bitmap> req = mLoadedPreviews.remove(key);
- if (req != null && req.get() != null) {
- mUnusedBitmaps.add(req.get());
- }
- }
- }
-
try {
mDb.getWritableDatabase().delete(CacheDb.TABLE_NAME,
CacheDb.COLUMN_PACKAGE + " = ? AND " + CacheDb.COLUMN_USER + " = ?",
@@ -223,11 +206,14 @@
* 2. Any preview for an absent package is removed
* This ensures that we remove entries for packages which changed while the launcher was dead.
*/
- public void removeObsoletePreviews() {
+ public void removeObsoletePreviews(ArrayList<Object> list) {
+ // This method should always be called from the worker thread.
+ Assert.assertTrue(LauncherModel.sWorkerThread.getThreadId() == Process.myTid());
+
LongSparseArray<UserHandleCompat> userIdCache = new LongSparseArray<>();
LongSparseArray<HashSet<String>> validPackages = new LongSparseArray<>();
- for (Object obj : LauncherModel.getSortedWidgetsAndShortcuts(mContext, false)) {
+ for (Object obj : list) {
final UserHandleCompat user;
final String pkg;
if (obj instanceof ResolveInfo) {
@@ -549,26 +535,25 @@
public class PreviewLoadRequest {
private final PreviewLoadTask mTask;
- private final WidgetCacheKey mKey;
- public PreviewLoadRequest(PreviewLoadTask task, WidgetCacheKey key) {
+ public PreviewLoadRequest(PreviewLoadTask task) {
mTask = task;
- mKey = key;
}
- public void cancel(boolean recycleImage) {
+ public void cleanup() {
if (mTask != null) {
mTask.cancel(true);
}
- if (recycleImage) {
- synchronized(mLoadedPreviews) {
- WeakReference<Bitmap> result = mLoadedPreviews.remove(mKey);
- if (result != null && result.get() != null) {
- mUnusedBitmaps.add(result.get());
- }
- }
+ if (mTask.mBitmap == null) {
+ return;
}
+
+ // The preview is no longer bound to any view, move it to {@link WeakReference} list.
+ synchronized(mUnusedBitmaps) {
+ mUnusedBitmaps.add(mTask.mBitmap);
+ }
+ mTask.mBitmap = null;
}
}
@@ -579,6 +564,7 @@
private final int mPreviewHeight;
private final int mPreviewWidth;
private final WidgetCell mCaller;
+ private Bitmap mBitmap;
PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth,
int previewHeight, WidgetCell caller) {
@@ -597,7 +583,6 @@
protected Bitmap doInBackground(Void... params) {
Bitmap unusedBitmap = null;
- // TODO(hyunyoungs): Figure out why this path causes concurrency issue.
synchronized (mUnusedBitmaps) {
// Check if we can use a bitmap
for (Bitmap candidate : mUnusedBitmaps) {
@@ -638,10 +623,7 @@
@Override
protected void onPostExecute(Bitmap result) {
- synchronized(mLoadedPreviews) {
- mLoadedPreviews.put(mKey, new WeakReference<Bitmap>(result));
- }
-
+ mBitmap = result;
mCaller.applyPreview(result);
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 9acdcae..e7a41e0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -60,6 +60,7 @@
import com.android.launcher3.FolderIcon.FolderRingAnimator;
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.Launcher.LauncherOverlay;
+import com.android.launcher3.LauncherAccessibilityDelegate.AccessibilityDragSource;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.UninstallDropTarget.UninstallSource;
import com.android.launcher3.compat.UserHandleCompat;
@@ -82,7 +83,7 @@
public class Workspace extends SmoothPagedView
implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
- Insettable, UninstallSource {
+ Insettable, UninstallSource, AccessibilityDragSource {
private static final String TAG = "Launcher.Workspace";
private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
@@ -125,6 +126,7 @@
@Thunk Runnable mRemoveEmptyScreenRunnable;
@Thunk boolean mDeferRemoveExtraEmptyScreen = false;
+ @Thunk boolean mAddNewPageOnDrag = true;
/**
* CellInfo for the cell that is currently being dragged
@@ -390,7 +392,7 @@
post(new Runnable() {
@Override
public void run() {
- if (mIsDragOccuring) {
+ if (mIsDragOccuring && mAddNewPageOnDrag) {
mDeferRemoveExtraEmptyScreen = false;
addExtraEmptyScreenOnDrag();
}
@@ -398,6 +400,9 @@
});
}
+ public void setAddNewPageOnDrag(boolean addPage) {
+ mAddNewPageOnDrag = addPage;
+ }
public void deferRemoveExtraEmptyScreen() {
mDeferRemoveExtraEmptyScreen = true;
@@ -562,7 +567,7 @@
LauncherAccessibilityDelegate delegate =
LauncherAppState.getInstance().getAccessibilityDelegate();
if (delegate != null && delegate.isInAccessibleDrag()) {
- newScreen.enableAccessibleDrag(true);
+ newScreen.enableAccessibleDrag(true, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
}
return screenId;
}
@@ -1601,10 +1606,11 @@
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @Override
public void enableAccessibleDrag(boolean enable) {
for (int i = 0; i < getChildCount(); i++) {
CellLayout child = (CellLayout) getChildAt(i);
- child.enableAccessibleDrag(enable);
+ child.enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
}
if (enable) {
@@ -1615,7 +1621,8 @@
setOnClickListener(mLauncher);
}
mLauncher.getSearchBar().enableAccessibleDrag(enable);
- mLauncher.getHotseat().getLayout().enableAccessibleDrag(enable);
+ mLauncher.getHotseat().getLayout()
+ .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
}
public boolean hasCustomContent() {
@@ -2253,6 +2260,7 @@
startDrag(cellInfo, false);
}
+ @Override
public void startDrag(CellLayout.CellInfo cellInfo, boolean accessible) {
View child = cellInfo.cell;
@@ -2616,6 +2624,9 @@
return false;
}
+ @Override
+ public void prepareAccessibilityDrop() { }
+
public void onDrop(final DragObject d) {
mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
CellLayout dropTargetLayout = mDropToLayout;
@@ -3897,7 +3908,7 @@
}
@Override
- public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
+ public void onFlingToDelete(DragObject d, PointF vec) {
// Do nothing
}
diff --git a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
new file mode 100644
index 0000000..0f17241
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 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.accessibility;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.LauncherAccessibilityDelegate;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+
+import java.util.List;
+
+/**
+ * Helper class to make drag-and-drop in a {@link CellLayout} accessible.
+ */
+public abstract class DragAndDropAccessibilityDelegate extends ExploreByTouchHelper
+ implements OnClickListener {
+ protected static final int INVALID_POSITION = -1;
+
+ private static final int[] sTempArray = new int[2];
+
+ protected final CellLayout mView;
+ protected final Context mContext;
+ protected final LauncherAccessibilityDelegate mDelegate;
+
+ private final Rect mTempRect = new Rect();
+
+ public DragAndDropAccessibilityDelegate(CellLayout forView) {
+ super(forView);
+ mView = forView;
+ mContext = mView.getContext();
+ mDelegate = LauncherAppState.getInstance().getAccessibilityDelegate();
+ }
+
+ @Override
+ protected int getVirtualViewAt(float x, float y) {
+ if (x < 0 || y < 0 || x > mView.getMeasuredWidth() || y > mView.getMeasuredHeight()) {
+ return INVALID_ID;
+ }
+ mView.pointToCellExact((int) x, (int) y, sTempArray);
+
+ // Map cell to id
+ int id = sTempArray[0] + sTempArray[1] * mView.getCountX();
+ return intersectsValidDropTarget(id);
+ }
+
+ /**
+ * @return the view id of the top left corner of a valid drop region or
+ * {@link #INVALID_POSITION} if there is no such valid region.
+ */
+ protected abstract int intersectsValidDropTarget(int id);
+
+ @Override
+ protected void getVisibleVirtualViews(List<Integer> virtualViews) {
+ // We create a virtual view for each cell of the grid
+ // The cell ids correspond to cells in reading order.
+ int nCells = mView.getCountX() * mView.getCountY();
+
+ for (int i = 0; i < nCells; i++) {
+ if (intersectsValidDropTarget(i) == i) {
+ virtualViews.add(i);
+ }
+ }
+ }
+
+ @Override
+ protected boolean onPerformActionForVirtualView(int viewId, int action, Bundle args) {
+ if (action == AccessibilityNodeInfoCompat.ACTION_CLICK && viewId != INVALID_ID) {
+ String confirmation = getConfirmationForIconDrop(viewId);
+ mDelegate.handleAccessibleDrop(mView, getItemBounds(viewId), confirmation);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onClick(View v) {
+ onPerformActionForVirtualView(getFocusedVirtualView(),
+ AccessibilityNodeInfoCompat.ACTION_CLICK, null);
+ }
+
+ @Override
+ protected void onPopulateEventForVirtualView(int id, AccessibilityEvent event) {
+ if (id == INVALID_ID) {
+ throw new IllegalArgumentException("Invalid virtual view id");
+ }
+ event.setContentDescription(mContext.getString(R.string.action_move_here));
+ }
+
+ @Override
+ protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
+ if (id == INVALID_ID) {
+ throw new IllegalArgumentException("Invalid virtual view id");
+ }
+
+ node.setContentDescription(getLocationDescriptionForIconDrop(id));
+ node.setBoundsInParent(getItemBounds(id));
+
+ node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
+ node.setClickable(true);
+ node.setFocusable(true);
+ }
+
+ protected abstract String getLocationDescriptionForIconDrop(int id);
+
+ protected abstract String getConfirmationForIconDrop(int id);
+
+ private Rect getItemBounds(int id) {
+ int cellX = id % mView.getCountX();
+ int cellY = id / mView.getCountX();
+ LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+ mView.cellToRect(cellX, cellY, dragInfo.info.spanX, dragInfo.info.spanY, mTempRect);
+ return mTempRect;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java b/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java
new file mode 100644
index 0000000..fc105b4
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 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.accessibility;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.FolderPagedView;
+import com.android.launcher3.R;
+
+/**
+ * Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD in a folder.
+ */
+public class FolderAccessibilityHelper extends DragAndDropAccessibilityDelegate {
+ private final int mStartPosition;
+
+ public FolderAccessibilityHelper(CellLayout layout) {
+ super(layout);
+ FolderPagedView parent = (FolderPagedView) layout.getParent();
+
+ int index = parent.indexOfChild(layout);
+ mStartPosition = 1 + index * layout.getCountX() * layout.getCountY();
+ }
+ @Override
+ protected int intersectsValidDropTarget(int id) {
+ return id;
+ }
+
+ @Override
+ protected String getLocationDescriptionForIconDrop(int id) {
+ return mContext.getString(R.string.move_to_position, id + mStartPosition);
+ }
+
+ @Override
+ protected String getConfirmationForIconDrop(int id) {
+ return mContext.getString(R.string.item_moved);
+ }
+}
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
new file mode 100644
index 0000000..42e9e3c
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2015 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.accessibility;
+
+import android.text.TextUtils;
+import android.view.View;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAccessibilityDelegate;
+import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+
+/**
+ * Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD on workspace.
+ */
+public class WorkspaceAccessibilityHelper extends DragAndDropAccessibilityDelegate {
+
+ public WorkspaceAccessibilityHelper(CellLayout layout) {
+ super(layout);
+ }
+
+ /**
+ * Find the virtual view id corresponding to the top left corner of any drop region by which
+ * the passed id is contained. For an icon, this is simply
+ */
+ @Override
+ protected int intersectsValidDropTarget(int id) {
+ int mCountX = mView.getCountX();
+ int mCountY = mView.getCountY();
+
+ int x = id % mCountX;
+ int y = id / mCountX;
+ LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+ if (dragInfo.dragType == DragType.WIDGET && mView.isHotseat()) {
+ return INVALID_POSITION;
+ }
+
+ if (dragInfo.dragType == DragType.WIDGET) {
+ // For a widget, every cell must be vacant. In addition, we will return any valid
+ // drop target by which the passed id is contained.
+ boolean fits = false;
+
+ // These represent the amount that we can back off if we hit a problem. They
+ // get consumed as we move up and to the right, trying new regions.
+ int spanX = dragInfo.info.spanX;
+ int spanY = dragInfo.info.spanY;
+
+ for (int m = 0; m < spanX; m++) {
+ for (int n = 0; n < spanY; n++) {
+
+ fits = true;
+ int x0 = x - m;
+ int y0 = y - n;
+
+ if (x0 < 0 || y0 < 0) continue;
+
+ for (int i = x0; i < x0 + spanX; i++) {
+ if (!fits) break;
+ for (int j = y0; j < y0 + spanY; j++) {
+ if (i >= mCountX || j >= mCountY || mView.isOccupied(i, j)) {
+ fits = false;
+ break;
+ }
+ }
+ }
+ if (fits) {
+ return x0 + mCountX * y0;
+ }
+ }
+ }
+ return INVALID_POSITION;
+ } else {
+ // For an icon, we simply check the view directly below
+ View child = mView.getChildAt(x, y);
+ if (child == null || child == dragInfo.item) {
+ // Empty cell. Good for an icon or folder.
+ return id;
+ } else if (dragInfo.dragType != DragType.FOLDER) {
+ // For icons, we can consider cells that have another icon or a folder.
+ ItemInfo info = (ItemInfo) child.getTag();
+ if (info instanceof AppInfo || info instanceof FolderInfo ||
+ info instanceof ShortcutInfo) {
+ return id;
+ }
+ }
+ return INVALID_POSITION;
+ }
+ }
+
+ @Override
+ protected String getConfirmationForIconDrop(int id) {
+ int x = id % mView.getCountX();
+ int y = id / mView.getCountX();
+ LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+ View child = mView.getChildAt(x, y);
+ if (child == null || child == dragInfo.item) {
+ return mContext.getString(R.string.item_moved);
+ } else {
+ ItemInfo info = (ItemInfo) child.getTag();
+ if (info instanceof AppInfo || info instanceof ShortcutInfo) {
+ return mContext.getString(R.string.folder_created);
+
+ } else if (info instanceof FolderInfo) {
+ return mContext.getString(R.string.added_to_folder);
+ }
+ }
+ return "";
+ }
+
+ @Override
+ protected String getLocationDescriptionForIconDrop(int id) {
+ int x = id % mView.getCountX();
+ int y = id / mView.getCountX();
+ LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+ View child = mView.getChildAt(x, y);
+ if (child == null || child == dragInfo.item) {
+ if (mView.isHotseat()) {
+ return mContext.getString(R.string.move_to_hotseat_position, id + 1);
+ } else {
+ return mContext.getString(R.string.move_to_empty_cell, y + 1, x + 1);
+ }
+ } else {
+ ItemInfo info = (ItemInfo) child.getTag();
+ if (info instanceof ShortcutInfo) {
+ return mContext.getString(R.string.create_folder_with, info.title);
+ } else if (info instanceof FolderInfo) {
+ if (TextUtils.isEmpty(info.title.toString().trim())) {
+ // Find the first item in the folder.
+ FolderInfo folder = (FolderInfo) info;
+ ShortcutInfo firstItem = null;
+ for (ShortcutInfo shortcut : folder.contents) {
+ if (firstItem == null || firstItem.rank > shortcut.rank) {
+ firstItem = shortcut;
+ }
+ }
+
+ if (firstItem != null) {
+ return mContext.getString(R.string.add_to_folder_with_app, firstItem.title);
+ }
+ }
+ return mContext.getString(R.string.add_to_folder, info.title);
+ }
+ }
+ return "";
+ }
+}
diff --git a/src/com/android/launcher3/util/FlingAnimation.java b/src/com/android/launcher3/util/FlingAnimation.java
new file mode 100644
index 0000000..55c5d7d
--- /dev/null
+++ b/src/com/android/launcher3/util/FlingAnimation.java
@@ -0,0 +1,104 @@
+package com.android.launcher3.util;
+
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.DragLayer;
+import com.android.launcher3.DragView;
+import com.android.launcher3.DropTarget.DragObject;
+
+public class FlingAnimation implements AnimatorUpdateListener {
+
+ /**
+ * Maximum acceleration in one dimension (pixels per milliseconds)
+ */
+ private static final float MAX_ACCELERATION = 0.5f;
+ private static final int DRAG_END_DELAY = 300;
+
+ protected final DragObject mDragObject;
+ protected final Rect mIconRect;
+ protected final DragLayer mDragLayer;
+ protected final Rect mFrom;
+ protected final int mDuration;
+ protected final float mUX, mUY;
+ protected final float mAnimationTimeFraction;
+ protected final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
+
+ protected float mAX, mAY;
+
+ /**
+ * @param vel initial fling velocity in pixels per second.
+ */
+ public FlingAnimation(DragObject d, PointF vel, Rect iconRect, DragLayer dragLayer) {
+ mDragObject = d;
+ mUX = vel.x / 1000;
+ mUY = vel.y / 1000;
+ mIconRect = iconRect;
+
+ mDragLayer = dragLayer;
+ mFrom = new Rect();
+ dragLayer.getViewRectRelativeToSelf(d.dragView, mFrom);
+
+ float scale = d.dragView.getScaleX();
+ float xOffset = ((scale - 1f) * d.dragView.getMeasuredWidth()) / 2f;
+ float yOffset = ((scale - 1f) * d.dragView.getMeasuredHeight()) / 2f;
+ mFrom.left += xOffset;
+ mFrom.right -= xOffset;
+ mFrom.top += yOffset;
+ mFrom.bottom -= yOffset;
+
+ mDuration = initDuration();
+ mAnimationTimeFraction = ((float) mDuration) / (mDuration + DRAG_END_DELAY);
+ }
+
+ /**
+ * The fling animation is based on the following system
+ * - Apply a constant force in the y direction to causing the fling to decelerate.
+ * - The animation runs for the time taken by the object to go out of the screen.
+ * - Calculate a constant acceleration in x direction such that the object reaches
+ * {@link #mIconRect} in the given time.
+ */
+ protected int initDuration() {
+ float sY = -mFrom.bottom;
+
+ float d = mUY * mUY + 2 * sY * MAX_ACCELERATION;
+ if (d >= 0) {
+ // sY can be reached under the MAX_ACCELERATION. Use MAX_ACCELERATION for y direction.
+ mAY = MAX_ACCELERATION;
+ } else {
+ // sY is not reachable, decrease the acceleration so that sY is almost reached.
+ d = 0;
+ mAY = mUY * mUY / (2 * -sY);
+ }
+ double t = (-mUY - Math.sqrt(d)) / mAY;
+
+ float sX = -mFrom.exactCenterX() + mIconRect.exactCenterX();
+
+ // Find horizontal acceleration such that: u*t + a*t*t/2 = s
+ mAX = (float) ((sX - t * mUX) * 2 / (t * t));
+ return (int) Math.round(t);
+ }
+
+ public final int getDuration() {
+ return mDuration + DRAG_END_DELAY;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = animation.getAnimatedFraction();
+ if (t > mAnimationTimeFraction) {
+ t = 1;
+ } else {
+ t = t / mAnimationTimeFraction;
+ }
+ final DragView dragView = (DragView) mDragLayer.getAnimatedView();
+ final float time = t * mDuration;
+ dragView.setTranslationX(time * mUX + mFrom.left + mAX * time * time / 2);
+ dragView.setTranslationY(time * mUY + mFrom.top + mAY * time * time / 2);
+ dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 0bc7333..2df170e 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -48,7 +48,7 @@
private static final String TAG = "WidgetCell";
private static final boolean DEBUG = false;
- private static final int FADE_IN_DURATION_MS = 70;
+ private static final int FADE_IN_DURATION_MS = 90;
private int mPresetPreviewSize;
private ImageView mWidgetImage;
@@ -94,16 +94,25 @@
mOriginalImagePadding.right = mWidgetImage.getPaddingRight();
mOriginalImagePadding.bottom = mWidgetImage.getPaddingBottom();
- // Ensure we are using the right text size
- DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
mWidgetName = ((TextView) findViewById(R.id.widget_name));
mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
}
- public void reset() {
+ /**
+ * Called to clear the view and free attached resources. (e.g., {@link Bitmap}
+ */
+ public void clear() {
+ if (DEBUG) {
+ Log.d(TAG, "reset called on:" + mWidgetName.getText());
+ }
mWidgetImage.setImageDrawable(null);
mWidgetName.setText(null);
mWidgetDims.setText(null);
+
+ if (mActiveRequest != null) {
+ mActiveRequest.cleanup();
+ mActiveRequest = null;
+ }
}
/**
@@ -140,16 +149,6 @@
mWidgetPreviewLoader = loader;
}
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- deletePreview(false);
-
- if (DEBUG) {
- Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
- }
- }
-
public int[] getPreviewSize() {
int[] maxSize = new int[2];
maxSize[0] = mPresetPreviewSize;
@@ -219,16 +218,6 @@
return Math.min(size[0], info.spanX * cellWidth);
}
-
- private void deletePreview(boolean recycleImage) {
- mWidgetImage.setImageDrawable(null);
-
- if (mActiveRequest != null) {
- mActiveRequest.cancel(recycleImage);
- mActiveRequest = null;
- }
- }
-
/**
* Helper method to get the string info of the tag.
*/
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 27a3ea1..22e29f3 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -24,9 +24,9 @@
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.State;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -61,11 +61,11 @@
private static final String TAG = "WidgetsContainerView";
private static final boolean DEBUG = false;
- /* {@link RecyclerView} will keep following # of views in cache, before recycling. */
- private static final int WIDGET_CACHE_SIZE = 2;
-
private static final int SPRING_MODE_DELAY_MS = 150;
+ /* Coefficient multiplied to the screen height for preloading widgets. */
+ private static final int PRELOAD_SCREEN_HEIGHT_MULTIPLE = 1;
+
/* Global instances that are used inside this container. */
private Launcher mLauncher;
private DragController mDragController;
@@ -118,9 +118,15 @@
}
mView = (RecyclerView) findViewById(R.id.widgets_list_view);
mView.setAdapter(mAdapter);
- mView.setLayoutManager(new LinearLayoutManager(getContext()));
- mView.setItemViewCacheSize(WIDGET_CACHE_SIZE);
+ // This extends the layout space so that preloading happen for the {@link RecyclerView}
+ mView.setLayoutManager(new LinearLayoutManager(getContext()) {
+ @Override
+ protected int getExtraLayoutSpace(State state) {
+ return super.getExtraLayoutSpace(state)
+ + WidgetsContainerView.this.getHeight() * PRELOAD_SCREEN_HEIGHT_MULTIPLE;
+ }
+ });
mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
getPaddingBottom());
}
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index f6ab21e..a7728a1 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -120,14 +120,15 @@
mIconCache.getTitleAndIconForApp(infoOut.packageName,
UserHandleCompat.myUserHandle(), false /* useLowResIcon */, infoOut);
}
- ((TextView) holder.getContent().findViewById(R.id.section)).setText(infoOut.title);
+
+ TextView tv = ((TextView) holder.getContent().findViewById(R.id.section));
+ tv.setText(infoOut.title);
ImageView iv = (ImageView) holder.getContent().findViewById(R.id.section_image);
iv.setImageBitmap(infoOut.iconBitmap);
// Bind the view in the widget horizontal tray region.
for (int i=0; i < infoList.size(); i++) {
WidgetCell widget = (WidgetCell) row.getChildAt(i);
- widget.reset();
if (getWidgetPreviewLoader() == null) {
return;
}
@@ -150,7 +151,7 @@
@Override
public WidgetsRowViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (DEBUG) {
- Log.v(TAG, String.format("\nonCreateViewHolder, [widget#=%d]", viewType));
+ Log.v(TAG, "\nonCreateViewHolder");
}
ViewGroup container = (ViewGroup) mLayoutInflater.inflate(
@@ -159,6 +160,16 @@
}
@Override
+ public void onViewRecycled(WidgetsRowViewHolder holder) {
+ ViewGroup row = ((ViewGroup) holder.getContent().findViewById(R.id.widgets_cell_list));
+
+ for (int i = 0; i < row.getChildCount(); i++) {
+ WidgetCell widget = (WidgetCell) row.getChildAt(i);
+ widget.clear();
+ }
+ }
+
+ @Override
public long getItemId(int pos) {
return pos;
}
diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
index 99a192c..249559a 100644
--- a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
+++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
@@ -25,7 +25,7 @@
ViewGroup mContent;
- public WidgetsRowViewHolder(ViewGroup v) {
+ public WidgetsRowViewHolder(ViewGroup v) {
super(v);
mContent = v;
}