Merge "Deduping shortcuts to app-shortcuts if they have a valid intent" into ub-launcher3-burnaby
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f43106f..b61b90c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -192,15 +192,6 @@
</intent-filter>
</receiver>
- <!-- New user initialization; set up initial wallpaper -->
- <receiver
- android:name="com.android.launcher3.UserInitializeReceiver"
- android:exported="false">
- <intent-filter>
- <action android:name="android.intent.action.USER_INITIALIZE" />
- </intent-filter>
- </receiver>
-
<receiver android:name="com.android.launcher3.StartupReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
diff --git a/res/drawable/apps_list_bg.xml b/res/drawable/apps_list_bg.xml
index 64177c1..0e56684 100644
--- a/res/drawable/apps_list_bg.xml
+++ b/res/drawable/apps_list_bg.xml
@@ -14,7 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/apps_list_bg_inset"
- android:insetLeft="@dimen/apps_container_inset"
- android:insetRight="@dimen/apps_container_inset" />
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#ffffff" />
+ <corners
+ android:radius="2dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/apps_list_search_bg.xml b/res/drawable/apps_list_search_bg.xml
index eda33a9..63c4d55 100644
--- a/res/drawable/apps_list_search_bg.xml
+++ b/res/drawable/apps_list_search_bg.xml
@@ -18,6 +18,6 @@
android:shape="rectangle">
<solid android:color="#ffffff" />
<corners
- android:topLeftRadius="3dp"
- android:topRightRadius="3dp" />
+ android:bottomLeftRadius="2dp"
+ android:bottomRightRadius="2dp" />
</shape>
\ No newline at end of file
diff --git a/res/drawable/apps_reveal_bg.xml b/res/drawable/apps_reveal_bg.xml
index 47c608f..07505a5 100644
--- a/res/drawable/apps_reveal_bg.xml
+++ b/res/drawable/apps_reveal_bg.xml
@@ -14,7 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/apps_reveal_bg_inset"
- android:insetLeft="@dimen/apps_container_inset"
- android:insetRight="@dimen/apps_container_inset" />
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#ffffff" />
+ <corners android:radius="2dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/apps_reveal_bg_inset.xml b/res/drawable/apps_reveal_bg_inset.xml
deleted file mode 100644
index 61f1c08..0000000
--- a/res/drawable/apps_reveal_bg_inset.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="#ffffff" />
- <corners android:radius="3dp" />
-</shape>
\ No newline at end of file
diff --git a/res/drawable/apps_list_bg_inset.xml b/res/drawable/apps_search_bg.xml
similarity index 90%
rename from res/drawable/apps_list_bg_inset.xml
rename to res/drawable/apps_search_bg.xml
index 5ea7895..405e844 100644
--- a/res/drawable/apps_list_bg_inset.xml
+++ b/res/drawable/apps_search_bg.xml
@@ -18,6 +18,6 @@
android:shape="rectangle">
<solid android:color="#ffffff" />
<corners
- android:bottomLeftRadius="3dp"
- android:bottomRightRadius="3dp" />
+ android:topLeftRadius="2dp"
+ android:topRightRadius="2dp" />
</shape>
\ No newline at end of file
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index b13984a..d5dd91a 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -57,8 +57,8 @@
android:id="@+id/overview_panel"
android:visibility="gone" />
- <include layout="@layout/apps_customize_pane"
- android:id="@+id/apps_customize_pane"
+ <include layout="@layout/widgets_view"
+ android:id="@+id/widgets_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 3cb338e..5a018c5 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -66,8 +66,8 @@
android:id="@+id/search_drop_target_bar"
layout="@layout/search_drop_target_bar" />
- <include layout="@layout/apps_customize_pane"
- android:id="@+id/apps_customize_pane"
+ <include layout="@layout/widgets_view"
+ android:id="@+id/widgets_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
diff --git a/res/layout-sw600dp/apps_view.xml b/res/layout-sw600dp/apps_view.xml
index fba170b..e6e0ec3 100644
--- a/res/layout-sw600dp/apps_view.xml
+++ b/res/layout-sw600dp/apps_view.xml
@@ -19,7 +19,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/apps_container_inset"
- android:background="@drawable/apps_customize_bg"
android:descendantFocusability="afterDescendants">
<include
layout="@layout/apps_reveal_view"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index a3d502c..a9601af 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -66,8 +66,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
- <include layout="@layout/apps_customize_pane"
- android:id="@+id/apps_customize_pane"
+ <include layout="@layout/widgets_view"
+ android:id="@+id/widgets_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
deleted file mode 100644
index e42576f..0000000
--- a/res/layout/apps_customize_pane.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.launcher3.AppsCustomizeTabHost
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:clipChildren="false">
-
- <LinearLayout
- android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:orientation="vertical">
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:clipChildren="false">
- <FrameLayout
- android:id="@+id/fake_page_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false">
- <FrameLayout
- android:id="@+id/fake_page"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"
- android:clipToPadding="false" />
- </FrameLayout>
- <com.android.launcher3.AppsCustomizePagedView
- android:id="@+id/apps_customize_pane_content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x"
- launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y"
- launcher:maxGap="@dimen/workspace_max_gap"
- launcher:pageIndicator="@+id/apps_customize_page_indicator" />
- </FrameLayout>
- <include
- android:id="@+id/apps_customize_page_indicator"
- layout="@layout/page_indicator"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
- </LinearLayout>
-</com.android.launcher3.AppsCustomizeTabHost>
diff --git a/res/layout/apps_customize_widget.xml b/res/layout/apps_customize_widget.xml
deleted file mode 100644
index a8344e3..0000000
--- a/res/layout/apps_customize_widget.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.launcher3.PagedViewWidget
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
-
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:orientation="vertical"
-
- android:background="@drawable/focusable_view_bg"
- android:focusable="true">
-
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1">
- <FrameLayout
- android:id="@+id/left_border"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:background="@color/widget_text_panel"
- android:visibility="gone" />
-
- <!-- The preview of the widget or shortcut. -->
- <com.android.launcher3.PagedViewWidgetImageView
- android:id="@+id/widget_preview"
- style="@style/PagedViewWidgetImageView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:paddingTop="@dimen/app_widget_preview_padding_top"
- android:paddingEnd="@dimen/app_widget_preview_padding_right"
- android:paddingRight="@dimen/app_widget_preview_padding_right"
- android:scaleType="matrix" />
- <FrameLayout
- android:id="@+id/right_border"
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:background="@color/widget_text_panel"
- android:visibility="gone" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/app_widget_preview_label_vertical_padding"
- android:paddingBottom="@dimen/app_widget_preview_label_vertical_padding"
- android:paddingLeft="@dimen/app_widget_preview_label_horizontal_padding"
- android:paddingRight="@dimen/app_widget_preview_label_horizontal_padding"
- android:background="@color/widget_text_panel"
- android:orientation="horizontal">
- <!-- The name of the widget. -->
- <TextView
- android:id="@+id/widget_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="start"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
-
- android:textColor="#FFFFFFFF"
- android:textSize="12sp"
- android:textAlignment="viewStart"
- android:fontFamily="sans-serif-condensed"
- android:shadowRadius="2.0"
- android:shadowColor="#B0000000" />
-
- <!-- The original dimensions of the widget (can't be the same text as above due to different
- style. -->
- <TextView
- android:id="@+id/widget_dims"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginStart="5dp"
- android:layout_weight="0"
- android:gravity="start"
-
- android:textColor="#FFFFFFFF"
- android:textSize="12sp"
- android:fontFamily="sans-serif-condensed"
- android:shadowRadius="2.0"
- android:shadowColor="#B0000000" />
- </LinearLayout>
-
-
-</com.android.launcher3.PagedViewWidget>
diff --git a/res/layout/apps_list_row_view.xml b/res/layout/apps_list_row_view.xml
index 83c175b..e80285b 100644
--- a/res/layout/apps_list_row_view.xml
+++ b/res/layout/apps_list_row_view.xml
@@ -30,4 +30,4 @@
android:textColor="@color/apps_view_section_text_color"
android:textSize="@dimen/apps_view_section_text_size"
android:focusable="false" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/layout/apps_list_view.xml b/res/layout/apps_list_view.xml
index 3e42f84..595c46c 100644
--- a/res/layout/apps_list_view.xml
+++ b/res/layout/apps_list_view.xml
@@ -25,8 +25,6 @@
android:id="@+id/app_search_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/apps_container_inset"
- android:layout_marginRight="@dimen/apps_container_inset"
android:padding="16dp"
android:hint="@string/apps_view_search_bar_hint"
android:maxLines="1"
@@ -37,7 +35,7 @@
android:textColor="#4c4c4c"
android:textColorHint="#9c9c9c"
android:imeOptions="actionDone|flagNoExtractUi"
- android:background="@drawable/apps_list_search_bg"
+ android:background="@drawable/apps_search_bg"
android:elevation="4dp" />
<com.android.launcher3.AppsContainerRecyclerView
android:id="@+id/apps_list_view"
@@ -48,6 +46,5 @@
android:paddingBottom="12dp"
android:clipToPadding="false"
android:focusable="true"
- android:descendantFocusability="afterDescendants"
- android:background="@drawable/apps_list_bg" />
+ android:descendantFocusability="afterDescendants" />
</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/apps_reveal_view.xml b/res/layout/apps_reveal_view.xml
index bc93359..2951ea4 100644
--- a/res/layout/apps_reveal_view.xml
+++ b/res/layout/apps_reveal_view.xml
@@ -21,5 +21,4 @@
android:layout_gravity="center"
android:elevation="15dp"
android:visibility="invisible"
- android:background="@drawable/apps_reveal_bg"
android:focusable="false" />
\ No newline at end of file
diff --git a/res/layout/apps_view.xml b/res/layout/apps_view.xml
index 86d67e1..7f09f77 100644
--- a/res/layout/apps_view.xml
+++ b/res/layout/apps_view.xml
@@ -21,9 +21,6 @@
android:id="@+id/apps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="@dimen/apps_container_inset"
- android:paddingBottom="@dimen/apps_container_inset"
- android:background="@drawable/apps_customize_bg"
android:descendantFocusability="afterDescendants">
<include
layout="@layout/apps_reveal_view"
diff --git a/res/layout/page_indicator_marker.xml b/res/layout/page_indicator_marker.xml
index 686d275..564a958 100644
--- a/res/layout/page_indicator_marker.xml
+++ b/res/layout/page_indicator_marker.xml
@@ -16,8 +16,8 @@
<com.android.launcher3.PageIndicatorMarker
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="16dp"
- android:layout_height="16dp"
+ android:layout_width="12dp"
+ android:layout_height="12dp"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/inactive"
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index 7a4d5e8..cd3a051 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2008 The Android Open Source Project
+ 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.
@@ -34,30 +34,44 @@
android:layout_width="20dp"
android:layout_height="20dp" />
- <com.android.launcher3.FolderCellLayout
+ <com.android.launcher3.FolderPagedView
android:id="@+id/folder_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:cacheColorHint="#ff333333"
- android:hapticFeedbackEnabled="false" />
+ launcher:pageIndicator="@+id/folder_page_indicator" />
</FrameLayout>
- <com.android.launcher3.FolderEditText
- android:id="@+id/folder_name"
+ <LinearLayout
+ android:id="@+id/folder_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="#00000000"
- android:fontFamily="sans-serif-condensed"
- android:gravity="center_horizontal"
- android:hint="@string/folder_hint_text"
- android:imeOptions="flagNoExtractUi"
- android:paddingBottom="@dimen/folder_name_padding"
- android:paddingTop="@dimen/folder_name_padding"
- android:singleLine="true"
- android:textColor="#ff777777"
- android:textColorHighlight="#ffCCCCCC"
- android:textColorHint="#ff808080"
- android:textCursorDrawable="@null"
- android:textSize="14sp" />
+ android:orientation="vertical" >
+
+ <include
+ android:id="@+id/folder_page_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="12dp"
+ android:layout_gravity="center_horizontal"
+ layout="@layout/page_indicator" />
+
+ <com.android.launcher3.FolderEditText
+ android:id="@+id/folder_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:background="#00000000"
+ android:fontFamily="sans-serif-condensed"
+ android:gravity="center_horizontal"
+ android:hint="@string/folder_hint_text"
+ android:imeOptions="flagNoExtractUi"
+ android:paddingBottom="@dimen/folder_name_padding"
+ android:paddingTop="@dimen/folder_name_padding"
+ android:singleLine="true"
+ android:textColor="#ff777777"
+ android:textColorHighlight="#ffCCCCCC"
+ android:textColorHint="#ff808080"
+ android:textCursorDrawable="@null"
+ android:textSize="14sp" />
+ </LinearLayout>
</com.android.launcher3.Folder>
\ No newline at end of file
diff --git a/res/layout/user_folder_scroll.xml b/res/layout/user_folder_scroll.xml
deleted file mode 100644
index 12e5097..0000000
--- a/res/layout/user_folder_scroll.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-
-<com.android.launcher3.Folder xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/quantum_panel"
- android:orientation="vertical" >
-
- <FrameLayout
- android:id="@+id/folder_content_wrapper"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <!-- Actual size of the indicator doesn't matter as it is scaled to match the view size -->
-
- <com.android.launcher3.FocusIndicatorView
- android:id="@+id/focus_indicator"
- android:layout_width="20dp"
- android:layout_height="20dp" />
-
- <com.android.launcher3.FolderPagedView
- android:id="@+id/folder_content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- launcher:pageIndicator="@+id/folder_page_indicator" />
- </FrameLayout>
-
- <LinearLayout
- android:id="@+id/folder_footer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingStart="12dp"
- android:paddingEnd="8dp" >
-
- <com.android.launcher3.FolderEditText
- android:id="@+id/folder_name"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:background="#00000000"
- android:fontFamily="sans-serif-condensed"
- android:gravity="start"
- android:hint="@string/folder_hint_text"
- android:imeOptions="flagNoExtractUi"
- android:paddingBottom="@dimen/folder_name_padding"
- android:paddingTop="@dimen/folder_name_padding"
- android:singleLine="true"
- android:textColor="#ff777777"
- android:textColorHighlight="#ffCCCCCC"
- android:textColorHint="#ff808080"
- android:textCursorDrawable="@null"
- android:textSize="14sp" />
-
- <include
- android:id="@+id/folder_page_indicator"
- android:layout_width="wrap_content"
- android:layout_height="12dp"
- android:layout_gravity="top"
- android:layout_marginTop="5dp"
- layout="@layout/page_indicator" />
-
- <LinearLayout
- android:id="@+id/folder_sort"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_vertical"
- android:gravity="end|center_vertical" >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:text="@string/sort_alphabetical"
- android:textColor="#ff777777"
- android:textSize="14sp" />
-
- <Switch
- android:id="@+id/folder_sort_switch"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clickable="false"
- android:duplicateParentState="true"
- android:focusable="false" />
- </LinearLayout>
- </LinearLayout>
-
-</com.android.launcher3.Folder>
\ No newline at end of file
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
new file mode 100644
index 0000000..9e91f67
--- /dev/null
+++ b/res/layout/widget_cell.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.launcher3.widget.WidgetCell
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/widget_preview_label_vertical_padding"
+ android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
+ android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
+ android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
+ android:orientation="horizontal">
+
+ <!-- The name of the widget. -->
+ <TextView
+ android:id="@+id/widget_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="start"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+
+ android:textColor="#FFFFFFFF"
+ android:textSize="12sp"
+ android:textAlignment="viewStart"
+ android:fontFamily="sans-serif-condensed"
+ android:shadowRadius="2.0"
+ android:shadowColor="#B0000000" />
+
+ <!-- The original dimensions of the widget (can't be the same text as above due to different
+ style. -->
+ <TextView
+ android:id="@+id/widget_dims"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginStart="5dp"
+ android:layout_marginLeft="5dp"
+ android:layout_weight="0"
+ android:gravity="start"
+
+ android:textColor="#FFFFFFFF"
+ android:textSize="12sp"
+ android:fontFamily="sans-serif-condensed"
+ android:shadowRadius="2.0"
+ android:shadowColor="#B0000000" />
+ </LinearLayout>
+
+ <!-- The image of the widget. -->
+ <com.android.launcher3.widget.WidgetImageView
+ android:id="@+id/widget_preview"
+ style="@style/WidgetImageView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingTop="@dimen/widget_preview_padding_top"
+ android:paddingEnd="@dimen/widget_preview_padding_right"
+ android:paddingRight="@dimen/widget_preview_padding_right"
+ android:scaleType="matrix" />
+
+</com.android.launcher3.widget.WidgetCell>
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
new file mode 100644
index 0000000..017b450
--- /dev/null
+++ b/res/layout/widgets_list_row_view.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/widgets_cell_list_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg"
+ android:descendantFocusability="afterDescendants">
+
+ <!-- Section info -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ 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:background="@color/widget_text_panel"
+ />
+ <TextView
+ android:id="@+id/section"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/widget_section_height"
+ android:paddingTop="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:gravity="start|center_vertical"
+ android:textColor="@color/widgets_view_section_text_color"
+ android:background="@color/widget_text_panel"
+ android:textSize="20sp"
+ android:focusable="false" />
+ </LinearLayout>
+
+ <!-- Widget list -->
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
+ >
+ <!-- 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:scrollbars="none" >
+ <LinearLayout
+ android:id="@+id/widgets_cell_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" />
+ </HorizontalScrollView>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
new file mode 100644
index 0000000..8e7ed16
--- /dev/null
+++ b/res/layout/widgets_view.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<!-- The top and bottom paddings are defined in this container, but since we want
+ the list view to span the full width (for touch interception purposes), we
+ will bake the left/right padding into that view's background itself. -->
+<com.android.launcher3.widget.WidgetsContainerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/widgets_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="@dimen/widget_container_inset"
+ android:paddingBottom="@dimen/widget_container_inset"
+ android:descendantFocusability="afterDescendants">
+
+ <!-- Temporary until finalizing on animation. -->
+ <include
+ android:id="@+id/widgets_reveal_view"
+ layout="@layout/apps_reveal_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+
+ <LinearLayout
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:orientation="vertical">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/quantum_panel_dark"/>
+ </LinearLayout>
+</com.android.launcher3.widget.WidgetsContainerView>
\ No newline at end of file
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 1b34181..06a9984 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -18,9 +18,4 @@
<!-- QSB -->
<dimen name="toolbar_button_vertical_padding">8dip</dimen>
<dimen name="toolbar_button_horizontal_padding">0dip</dimen>
-
-<!-- AppsCustomize -->
- <dimen name="apps_customize_tab_bar_height">42dp</dimen>
- <integer name="apps_customize_widget_cell_count_x">3</integer>
- <integer name="apps_customize_widget_cell_count_y">2</integer>
</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index d80f18c..13a1f40 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -24,11 +24,9 @@
<dimen name="apps_view_row_height">76dp</dimen>
<!-- AppsCustomize -->
- <dimen name="apps_customize_tab_bar_height">60dp</dimen>
- <dimen name="apps_customize_tab_bar_margin_top">8dp</dimen>
- <dimen name="app_widget_preview_label_margin_top">8dp</dimen>
- <dimen name="app_widget_preview_label_margin_left">@dimen/app_widget_preview_padding_left</dimen>
- <dimen name="app_widget_preview_label_margin_right">@dimen/app_widget_preview_padding_right</dimen>
+ <dimen name="widget_preview_label_margin_top">8dp</dimen>
+ <dimen name="widget_preview_label_margin_left">@dimen/widget_preview_padding_left</dimen>
+ <dimen name="widget_preview_label_margin_right">@dimen/widget_preview_padding_right</dimen>
<!-- Cling -->
<dimen name="cling_migration_logo_height">400dp</dimen>
diff --git a/res/values-v17/styles.xml b/res/values-v17/styles.xml
index 11d2a1f..229375f 100644
--- a/res/values-v17/styles.xml
+++ b/res/values-v17/styles.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="PagedViewWidgetImageView">
- <item name="android:paddingStart">@dimen/app_widget_preview_padding_left</item>
+ <style name="WidgetImageView">
+ <item name="android:paddingStart">@dimen/widget_preview_padding_left</item>
</style>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 590a887..3a06bd9 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -36,8 +36,10 @@
<color name="outline_color">#FFFFFFFF</color>
<color name="widget_text_panel">#FF374248</color>
-<!-- Apps view -->
+ <!-- Apps view -->
<color name="apps_view_scrollbar_thumb_color">#009688</color>
<color name="apps_view_section_text_color">#009688</color>
+ <!-- Widgetss view -->
+ <color name="widgets_view_section_text_color">#009688</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 735373d..101b755 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -50,6 +50,8 @@
<dimen name="apps_container_width">0dp</dimen>
<dimen name="apps_container_height">0dp</dimen>
<dimen name="apps_container_inset">8dp</dimen>
+ <!-- Note: This needs to match the fixed insets for the search box -->
+ <dimen name="apps_container_fixed_bounds_inset">8dp</dimen>
<dimen name="apps_grid_view_start_margin">52dp</dimen>
<dimen name="apps_view_row_height">64dp</dimen>
<dimen name="apps_view_section_text_size">24sp</dimen>
@@ -60,18 +62,9 @@
<dimen name="apps_view_fast_scroll_text_size">40dp</dimen>
<!-- AllApps/Customize/AppsCustomize -->
- <!-- The height of the tab bar - if this changes, we should update the
- external icon width/height above to compensate -->
- <dimen name="apps_customize_tab_bar_height">52dp</dimen>
- <dimen name="apps_customize_tab_bar_margin_top">0dp</dimen>
<dimen name="app_icon_size">48dp</dimen>
<dimen name="apps_customize_horizontal_padding">0dp</dimen>
- <!-- The AppsCustomize page indicator -->
- <dimen name="apps_customize_page_indicator_height">12dp</dimen>
- <dimen name="apps_customize_page_indicator_margin">4dp</dimen>
- <dimen name="apps_customize_page_indicator_offset">16dp</dimen>
-
<!-- Drag padding to add to the bottom of drop targets -->
<dimen name="drop_target_drag_padding">14dp</dimen>
<dimen name="drop_target_text_size">14sp</dimen>
@@ -85,12 +78,19 @@
should be. If 0, it will not be scaled at all. -->
<dimen name="dragViewScale">12dp</dimen>
- <!-- Padding applied to AppWidget previews -->
- <dimen name="app_widget_preview_padding_left">16dp</dimen>
- <dimen name="app_widget_preview_padding_right">16dp</dimen>
- <dimen name="app_widget_preview_padding_top">32dp</dimen>
- <dimen name="app_widget_preview_label_vertical_padding">8dp</dimen>
- <dimen name="app_widget_preview_label_horizontal_padding">8dp</dimen>
+<!-- Widget tray -->
+ <dimen name="widget_container_inset">8dp</dimen>
+ <dimen name="widget_preview_size">140dp</dimen>
+ <dimen name="widget_preview_padding_left">16dp</dimen>
+ <dimen name="widget_preview_padding_right">16dp</dimen>
+ <dimen name="widget_preview_padding_top">8dp</dimen>
+ <dimen name="widget_preview_label_vertical_padding">8dp</dimen>
+ <dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
+
+ <dimen name="widget_section_height">52dp</dimen>
+ <dimen name="widget_section_icon_padding">8dp</dimen>
+
+ <dimen name="widget_cell_height">160dp</dimen>
<!-- Padding applied to shortcut previews -->
<dimen name="shortcut_preview_padding_left">0dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 77798f1..94efebc 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -91,8 +91,8 @@
</style>
<!-- Overridden in device overlays -->
- <style name="PagedViewWidgetImageView">
- <item name="android:paddingLeft">@dimen/app_widget_preview_padding_left</item>
+ <style name="WidgetImageView">
+ <item name="android:paddingLeft">@dimen/widget_preview_padding_left</item>
</style>
</resources>
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index a1391b2..7c6b066 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -43,7 +43,7 @@
/**
* A bitmap version of the application icon.
*/
- Bitmap iconBitmap;
+ public Bitmap iconBitmap;
/**
* Indicates whether we're using a low res icon
@@ -55,7 +55,7 @@
*/
long firstInstallTime;
- ComponentName componentName;
+ public ComponentName componentName;
static final int DOWNLOADED_FLAG = 1;
static final int UPDATED_SYSTEM_APP_FLAG = 2;
@@ -121,12 +121,15 @@
+ " user=" + user + ")";
}
+ /**
+ * Helper method used for debugging.
+ */
public static void dumpApplicationInfoList(String tag, String label, ArrayList<AppInfo> list) {
Log.d(tag, label + " size=" + list.size());
for (AppInfo info: list) {
- Log.d(tag, " title=\"" + info.title + "\" iconBitmap="
- + info.iconBitmap + " firstInstallTime="
- + info.firstInstallTime);
+ Log.d(tag, " title=\"" + info.title + "\" iconBitmap=" + info.iconBitmap
+ + " firstInstallTime=" + info.firstInstallTime
+ + " componentName=" + info.componentName.getPackageName());
}
}
diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java
index c93bacf..bb2aeb0 100644
--- a/src/com/android/launcher3/AppsContainerRecyclerView.java
+++ b/src/com/android/launcher3/AppsContainerRecyclerView.java
@@ -196,13 +196,27 @@
}
break;
case MotionEvent.ACTION_UP:
+ ViewConfiguration viewConfig = ViewConfiguration.get(getContext());
+ float dx = ev.getX() - mDownX;
+ float dy = ev.getY() - mDownY;
+ float distance = (float) Math.sqrt(dx * dx + dy * dy);
+ if (distance < viewConfig.getScaledTouchSlop()) {
+ Rect backgroundPadding = new Rect();
+ getBackground().getPadding(backgroundPadding);
+ boolean isOutsideBounds = ev.getX() < backgroundPadding.left ||
+ ev.getX() > (getWidth() - backgroundPadding.right);
+ if (isOutsideBounds) {
+ Launcher launcher = (Launcher) getContext();
+ launcher.showWorkspace(true);
+ }
+ }
+ // Fall through
case MotionEvent.ACTION_CANCEL:
mDraggingFastScroller = false;
animateFastScrollerVisibility(false);
break;
}
return mDraggingFastScroller;
-
}
/**
diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java
index 2de45cb..559f6eb 100644
--- a/src/com/android/launcher3/AppsContainerView.java
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -19,6 +19,7 @@
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.InsetDrawable;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.TextWatcher;
@@ -26,12 +27,13 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import android.widget.TextView;
-
import com.android.launcher3.util.Thunk;
import java.util.List;
@@ -59,8 +61,13 @@
private EditText mSearchBar;
private int mNumAppsPerRow;
private Point mLastTouchDownPos = new Point();
- private Rect mPadding = new Rect();
+ private Rect mInsets = new Rect();
+ private Rect mFixedBounds = new Rect();
private int mContentMarginStart;
+ // Normal container insets
+ private int mContainerInset;
+ // Fixed bounds container insets
+ private int mFixedBoundsContainerInset;
public AppsContainerView(Context context) {
this(context, null);
@@ -76,6 +83,10 @@
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
Resources res = context.getResources();
+ mContainerInset = context.getResources().getDimensionPixelSize(
+ R.dimen.apps_container_inset);
+ mFixedBoundsContainerInset = context.getResources().getDimensionPixelSize(
+ R.dimen.apps_container_fixed_bounds_inset);
mLauncher = (Launcher) context;
mApps = new AlphabeticalAppsList(context);
if (USE_LAYOUT == GRID_LAYOUT) {
@@ -126,6 +137,15 @@
}
/**
+ * Hides the search bar
+ */
+ public void hideSearchBar() {
+ mSearchBar.setVisibility(View.GONE);
+ updateBackgrounds();
+ updatePaddings();
+ }
+
+ /**
* Scrolls this list view to the top.
*/
public void scrollToTop() {
@@ -154,45 +174,58 @@
((AppsGridAdapter) mAdapter).setRtl(isRtl);
}
mSearchBar = (EditText) findViewById(R.id.app_search_box);
- mSearchBar.addTextChangedListener(this);
- mSearchBar.setOnEditorActionListener(this);
+ if (mSearchBar != null) {
+ mSearchBar.addTextChangedListener(this);
+ mSearchBar.setOnEditorActionListener(this);
+ }
mAppsListView = (AppsContainerRecyclerView) findViewById(R.id.apps_list_view);
mAppsListView.setApps(mApps);
mAppsListView.setNumAppsPerRow(mNumAppsPerRow);
mAppsListView.setLayoutManager(mLayoutManager);
mAppsListView.setAdapter(mAdapter);
mAppsListView.setHasFixedSize(true);
- if (isRtl) {
- mAppsListView.setPadding(
- mAppsListView.getPaddingLeft(),
- mAppsListView.getPaddingTop(),
- mAppsListView.getPaddingRight() + mContentMarginStart,
- mAppsListView.getPaddingBottom());
- } else {
- mAppsListView.setPadding(
- mAppsListView.getPaddingLeft() + mContentMarginStart,
- mAppsListView.getPaddingTop(),
- mAppsListView.getPaddingRight(),
- mAppsListView.getPaddingBottom());
- }
if (mItemDecoration != null) {
mAppsListView.addItemDecoration(mItemDecoration);
}
- mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
- getPaddingBottom());
+ updateBackgrounds();
+ updatePaddings();
}
@Override
public void setInsets(Rect insets) {
- setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
- mPadding.right + insets.right, mPadding.bottom + insets.bottom);
+ mInsets.set(insets);
+ updatePaddings();
+ }
+
+ /**
+ * Sets the fixed bounds for this Apps view.
+ */
+ public void setFixedBounds(Context context, Rect fixedBounds) {
+ if (!fixedBounds.isEmpty() && !fixedBounds.equals(mFixedBounds)) {
+ // Update the number of items in the grid
+ LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+ if (grid.updateAppsViewNumCols(context.getResources(), fixedBounds.width())) {
+ mNumAppsPerRow = grid.appsViewNumCols;
+ mAppsListView.setNumAppsPerRow(mNumAppsPerRow);
+ if (USE_LAYOUT == GRID_LAYOUT) {
+ ((AppsGridAdapter) mAdapter).setNumAppsPerRow(mNumAppsPerRow);
+ }
+ }
+
+ mFixedBounds.set(fixedBounds);
+ }
+ updateBackgrounds();
+ updatePaddings();
}
@Override
public boolean onTouch(View v, MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN ||
- ev.getAction() == MotionEvent.ACTION_MOVE) {
- mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
+ break;
}
return false;
}
@@ -359,7 +392,9 @@
public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
if (!toWorkspace) {
// Disable the focus so that the search bar doesn't get focus
- mSearchBar.setFocusableInTouchMode(false);
+ if (mSearchBar != null) {
+ mSearchBar.setFocusableInTouchMode(false);
+ }
}
}
@@ -375,11 +410,69 @@
@Override
public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
- if (toWorkspace) {
- // Clear the search bar
- mSearchBar.setText("");
- } else {
- mSearchBar.setFocusableInTouchMode(true);
+ if (mSearchBar != null) {
+ if (toWorkspace) {
+ // Clear the search bar
+ mSearchBar.setText("");
+ } else {
+ mSearchBar.setFocusableInTouchMode(true);
+ }
}
}
+
+ /**
+ * Update the padding of the Apps view and children. To ensure that the RecyclerView has the
+ * full width to handle touches right to the edge of the screen, we only apply the top and
+ * bottom padding to the AppsContainerView and then the left/right padding on the RecyclerView
+ * itself. In particular, the left/right padding is applied to the background of the view,
+ * and then additionally inset by the start margin.
+ */
+ private void updatePaddings() {
+ boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
+ LAYOUT_DIRECTION_RTL);
+ boolean hasSearchBar = (mSearchBar != null) && (mSearchBar.getVisibility() == View.VISIBLE);
+
+ if (mFixedBounds.isEmpty()) {
+ // If there are no fixed bounds, then use the default padding and insets
+ setPadding(mInsets.left, mContainerInset + mInsets.top, mInsets.right,
+ mContainerInset + mInsets.bottom);
+ } else {
+ // If there are fixed bounds, then we update the padding to reflect the fixed bounds.
+ setPadding(mFixedBounds.left, mFixedBounds.top + mFixedBoundsContainerInset,
+ getMeasuredWidth() - mFixedBounds.right,
+ mInsets.bottom + mFixedBoundsContainerInset);
+ }
+
+ // Update the apps recycler view
+ int inset = mFixedBounds.isEmpty() ? mContainerInset : mFixedBoundsContainerInset;
+ if (isRtl) {
+ mAppsListView.setPadding(inset, inset, inset + mContentMarginStart, inset);
+ } else {
+ mAppsListView.setPadding(inset + mContentMarginStart, inset, inset, inset);
+ }
+
+ // Update the search bar
+ if (hasSearchBar) {
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSearchBar.getLayoutParams();
+ lp.leftMargin = lp.rightMargin = inset;
+ }
+ }
+
+ /**
+ * Update the background of the Apps view and children.
+ */
+ private void updateBackgrounds() {
+ int inset = mFixedBounds.isEmpty() ? mContainerInset : mFixedBoundsContainerInset;
+ boolean hasSearchBar = (mSearchBar != null) && (mSearchBar.getVisibility() == View.VISIBLE);
+
+ // Update the background of the reveal view and list to be inset with the fixed bound
+ // insets instead of the default insets
+ mAppsListView.setBackground(new InsetDrawable(
+ getContext().getResources().getDrawable(
+ hasSearchBar ? R.drawable.apps_list_search_bg : R.drawable.apps_list_bg),
+ inset, 0, inset, 0));
+ getRevealView().setBackground(new InsetDrawable(
+ getContext().getResources().getDrawable(R.drawable.apps_reveal_bg),
+ inset, 0, inset, 0));
+ }
}
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
deleted file mode 100644
index 58bcf1d..0000000
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ /dev/null
@@ -1,1060 +0,0 @@
-/*
- * Copyright (C) 2011 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;
-
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.GridLayout;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.FocusHelper.PagedViewKeyListener;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.util.Thunk;
-
-import java.util.ArrayList;
-
-/**
- * The Apps/Customize page that displays all the applications, widgets, and shortcuts.
- */
-public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
- View.OnClickListener, DragSource,
- PagedViewWidget.ShortPressListener, LauncherTransitionable {
- static final String TAG = "AppsCustomizePagedView";
-
- private static Rect sTmpRect = new Rect();
- private static final int[] sTempPosArray = new int[2];
-
- /**
- * The different content types that this paged view can show.
- */
- public enum ContentType {
- Widgets
- }
- private ContentType mContentType = ContentType.Widgets;
-
- // Refs
- @Thunk Launcher mLauncher;
- private DragController mDragController;
- private final LayoutInflater mLayoutInflater;
- private final PackageManager mPackageManager;
-
- // Save and Restore
- private int mSaveInstanceStateItemIndex = -1;
-
- // Content
- private ArrayList<Object> mWidgets;
-
- // Caching
- private IconCache mIconCache;
-
- // Dimens
- private int mContentWidth, mContentHeight;
- @Thunk int mWidgetCountX, mWidgetCountY;
- private int mNumWidgetPages;
-
- private final PagedViewKeyListener mKeyListener = new PagedViewKeyListener();
-
- private Runnable mInflateWidgetRunnable = null;
- private Runnable mBindWidgetRunnable = null;
- static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
- static final int WIDGET_PRELOAD_PENDING = 0;
- static final int WIDGET_BOUND = 1;
- static final int WIDGET_INFLATED = 2;
- int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
- int mWidgetLoadingId = -1;
- PendingAddWidgetInfo mCreateWidgetInfo = null;
- private boolean mDraggingWidget = false;
- boolean mPageBackgroundsVisible = true;
-
- private Toast mWidgetInstructionToast;
-
- // Deferral of loading widget previews during launcher transitions
- private boolean mInTransition;
-
- WidgetPreviewLoader mWidgetPreviewLoader;
-
- private boolean mInBulkBind;
- private boolean mNeedToUpdatePageCountsAndInvalidateData;
-
- public AppsCustomizePagedView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mLayoutInflater = LayoutInflater.from(context);
- mPackageManager = context.getPackageManager();
- mWidgets = new ArrayList<>();
- mIconCache = (LauncherAppState.getInstance()).getIconCache();
-
- // Save the default widget preview background
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
- mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
- mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
- a.recycle();
-
- // The padding on the non-matched dimension for the default widget preview icons
- // (top + bottom)
- mFadeInAdjacentScreens = false;
-
- // Unless otherwise specified this view is important for accessibility.
- if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
- setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- }
- setSinglePageInViewport();
- }
-
- @Override
- protected void init() {
- super.init();
- mCenterPagesVertically = false;
-
- Context context = getContext();
- Resources r = context.getResources();
- setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f);
- }
-
- public void onFinishInflate() {
- super.onFinishInflate();
-
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- setPadding(grid.edgeMarginPx, 2 * grid.edgeMarginPx,
- grid.edgeMarginPx, 2 * grid.edgeMarginPx);
- }
-
- void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) {
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight);
- }
-
- WidgetPreviewLoader getWidgetPreviewLoader() {
- if (mWidgetPreviewLoader == null) {
- mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
- }
- return mWidgetPreviewLoader;
- }
-
- /** Returns the item index of the center item on this page so that we can restore to this
- * item index when we rotate. */
- private int getMiddleComponentIndexOnCurrentPage() {
- int i = -1;
- if (getPageCount() > 0) {
- int currentPage = getCurrentPage();
- if (mContentType == ContentType.Widgets) {
- PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
- int numItemsPerPage = mWidgetCountX * mWidgetCountY;
- int childCount = layout.getChildCount();
- if (childCount > 0) {
- i = (currentPage * numItemsPerPage) + (childCount / 2);
- }
- } else {
- throw new RuntimeException("Invalid ContentType");
- }
- }
- return i;
- }
-
- /** Get the index of the item to restore to if we need to restore the current page. */
- int getSaveInstanceStateIndex() {
- if (mSaveInstanceStateItemIndex == -1) {
- mSaveInstanceStateItemIndex = getMiddleComponentIndexOnCurrentPage();
- }
- return mSaveInstanceStateItemIndex;
- }
-
- /** Returns the page in the current orientation which is expected to contain the specified
- * item index. */
- int getPageForComponent(int index) {
- if (index < 0) return 0;
-
- int numItemsPerPage = mWidgetCountX * mWidgetCountY;
- return index / numItemsPerPage;
- }
-
- /** Restores the page for an item at the specified index */
- void restorePageForIndex(int index) {
- if (index < 0) return;
- mSaveInstanceStateItemIndex = index;
- }
-
- private void updatePageCounts() {
- mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
- (float) (mWidgetCountX * mWidgetCountY));
- }
-
- protected void onDataReady(int width, int height) {
- updatePageCounts();
-
- // Force a measure to update recalculate the gaps
- mContentWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
- mContentHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
-
- final boolean hostIsTransitioning = getTabHost().isInTransition();
- int page = getPageForComponent(mSaveInstanceStateItemIndex);
- invalidatePageData(Math.max(0, page), hostIsTransitioning);
- }
-
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
-
- if (!isDataReady()) {
- if (!mWidgets.isEmpty()) {
- post(new Runnable() {
- // This code triggers requestLayout so must be posted outside of the
- // layout pass.
- public void run() {
- if (Utilities.isViewAttachedToWindow(AppsCustomizePagedView.this)) {
- setDataIsReady();
- onDataReady(getMeasuredWidth(), getMeasuredHeight());
- }
- }
- });
- }
- }
- }
-
- public void onPackagesUpdated(ArrayList<Object> widgetsAndShortcuts) {
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
- // Get the list of widgets and shortcuts
- mWidgets.clear();
- for (Object o : widgetsAndShortcuts) {
- if (o instanceof LauncherAppWidgetProviderInfo) {
- LauncherAppWidgetProviderInfo widget = (LauncherAppWidgetProviderInfo) o;
- if (!app.shouldShowAppOrWidgetProvider(widget.provider) && !widget.isCustomWidget) {
- continue;
- }
-
- if (widget.minSpanX > 0 && widget.minSpanY > 0) {
- // Ensure that all widgets we show can be added on a workspace of this size
- int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget);
- int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, widget);
- int minSpanX = Math.min(spanXY[0], minSpanXY[0]);
- int minSpanY = Math.min(spanXY[1], minSpanXY[1]);
- if (minSpanX <= (int) grid.numColumns &&
- minSpanY <= (int) grid.numRows) {
- mWidgets.add(widget);
- } else {
- Log.e(TAG, "Widget " + widget.provider + " can not fit on this device (" +
- widget.minWidth + ", " + widget.minHeight + ")");
- }
- } else {
- Log.e(TAG, "Widget " + widget.provider + " has invalid dimensions (" +
- widget.minWidth + ", " + widget.minHeight + ")");
- }
- } else {
- // just add shortcuts
- mWidgets.add(o);
- }
- }
-
- updatePageCountsAndInvalidateData();
- }
-
- public void setBulkBind(boolean bulkBind) {
- if (bulkBind) {
- mInBulkBind = true;
- } else {
- mInBulkBind = false;
- if (mNeedToUpdatePageCountsAndInvalidateData) {
- updatePageCountsAndInvalidateData();
- }
- }
- }
-
- private void updatePageCountsAndInvalidateData() {
- if (mInBulkBind) {
- mNeedToUpdatePageCountsAndInvalidateData = true;
- } else {
- updatePageCounts();
- invalidateOnDataChange();
- mNeedToUpdatePageCountsAndInvalidateData = false;
- }
- }
-
- @Override
- public void onClick(View v) {
- // When we have exited all apps or are in transition, disregard clicks
- if (!mLauncher.isWidgetsViewVisible()
- || mLauncher.getWorkspace().isSwitchingState()
- || !(v instanceof PagedViewWidget)) return;
-
- // Let the user know that they have to long press to add a widget
- if (mWidgetInstructionToast != null) {
- mWidgetInstructionToast.cancel();
- }
- mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
- Toast.LENGTH_SHORT);
- mWidgetInstructionToast.show();
- }
-
- /*
- * PagedViewWithDraggableItems implementation
- */
- @Override
- protected void determineDraggingStart(android.view.MotionEvent ev) {
- }
-
- static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
- Bundle options = null;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, sTmpRect);
- Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
- info.componentName, null);
-
- float density = launcher.getResources().getDisplayMetrics().density;
- int xPaddingDips = (int) ((padding.left + padding.right) / density);
- int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
-
- options = new Bundle();
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
- sTmpRect.left - xPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
- sTmpRect.top - yPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
- sTmpRect.right - xPaddingDips);
- options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
- sTmpRect.bottom - yPaddingDips);
- }
- return options;
- }
-
- private void preloadWidget(final PendingAddWidgetInfo info) {
- final LauncherAppWidgetProviderInfo pInfo = info.info;
- final Bundle options = pInfo.isCustomWidget ? null :
- getDefaultOptionsForWidget(mLauncher, info);
-
- if (pInfo.configure != null) {
- info.bindOptions = options;
- return;
- }
-
- mWidgetCleanupState = WIDGET_PRELOAD_PENDING;
- mBindWidgetRunnable = new Runnable() {
- @Override
- public void run() {
- if (pInfo.isCustomWidget) {
- mWidgetCleanupState = WIDGET_BOUND;
- return;
- }
-
- mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
- if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
- mWidgetLoadingId, pInfo, options)) {
- mWidgetCleanupState = WIDGET_BOUND;
- }
-
- }
- };
- post(mBindWidgetRunnable);
-
- mInflateWidgetRunnable = new Runnable() {
- @Override
- public void run() {
- if (mWidgetCleanupState != WIDGET_BOUND) {
- return;
- }
- AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
- getContext(), mWidgetLoadingId, pInfo);
- info.boundWidget = hostView;
- mWidgetCleanupState = WIDGET_INFLATED;
- hostView.setVisibility(INVISIBLE);
- int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false);
-
- // We want the first widget layout to be the correct size. This will be important
- // for width size reporting to the AppWidgetManager.
- DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
- unScaledSize[1]);
- lp.x = lp.y = 0;
- lp.customPosition = true;
- hostView.setLayoutParams(lp);
- mLauncher.getDragLayer().addView(hostView);
- }
- };
- post(mInflateWidgetRunnable);
- }
-
- @Override
- public void onShortPress(View v) {
- // We are anticipating a long press, and we use this time to load bind and instantiate
- // the widget. This will need to be cleaned up if it turns out no long press occurs.
- if (mCreateWidgetInfo != null) {
- // Just in case the cleanup process wasn't properly executed. This shouldn't happen.
- cleanupWidgetPreloading(false);
- }
- mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
- preloadWidget(mCreateWidgetInfo);
- }
-
- private void cleanupWidgetPreloading(boolean widgetWasAdded) {
- if (!widgetWasAdded) {
- // If the widget was not added, we may need to do further cleanup.
- PendingAddWidgetInfo info = mCreateWidgetInfo;
- mCreateWidgetInfo = null;
-
- if (mWidgetCleanupState == WIDGET_PRELOAD_PENDING) {
- // We never did any preloading, so just remove pending callbacks to do so
- removeCallbacks(mBindWidgetRunnable);
- removeCallbacks(mInflateWidgetRunnable);
- } else if (mWidgetCleanupState == WIDGET_BOUND) {
- // Delete the widget id which was allocated
- if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
- mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
- }
-
- // We never got around to inflating the widget, so remove the callback to do so.
- removeCallbacks(mInflateWidgetRunnable);
- } else if (mWidgetCleanupState == WIDGET_INFLATED) {
- // Delete the widget id which was allocated
- if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
- mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
- }
-
- // The widget was inflated and added to the DragLayer -- remove it.
- AppWidgetHostView widget = info.boundWidget;
- mLauncher.getDragLayer().removeView(widget);
- }
- }
- mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
- mWidgetLoadingId = -1;
- mCreateWidgetInfo = null;
- PagedViewWidget.resetShortPressTarget();
- }
-
- @Override
- public void cleanUpShortPress(View v) {
- if (!mDraggingWidget) {
- cleanupWidgetPreloading(false);
- }
- }
-
- private boolean beginDraggingWidget(PagedViewWidget v) {
- mDraggingWidget = true;
- // Get the widget preview as the drag representation
- ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
- PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
-
- // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
- // we abort the drag.
- if (image.getDrawable() == null) {
- mDraggingWidget = false;
- return false;
- }
-
- // Compose the drag image
- Bitmap preview;
- Bitmap outline;
- float scale = 1f;
- Point previewPadding = null;
-
- if (createItemInfo instanceof PendingAddWidgetInfo) {
- // This can happen in some weird cases involving multi-touch. We can't start dragging
- // the widget if this is null, so we break out.
- if (mCreateWidgetInfo == null) {
- return false;
- }
-
- PendingAddWidgetInfo createWidgetInfo = mCreateWidgetInfo;
- createItemInfo = createWidgetInfo;
- int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true);
-
- FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
- float minScale = 1.25f;
- int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
-
- int[] previewSizeBeforeScale = new int[1];
- preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
- maxWidth, null, previewSizeBeforeScale);
- // Compare the size of the drag preview to the preview in the AppsCustomize tray
- int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
- v.getActualItemWidth());
- scale = previewWidthInAppsCustomize / (float) preview.getWidth();
-
- // The bitmap in the AppsCustomize tray is always the the same size, so there
- // might be extra pixels around the preview itself - this accounts for that
- if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) {
- int padding =
- (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2;
- previewPadding = new Point(padding, 0);
- }
- } else {
- PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
- Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo);
- preview = Utilities.createIconBitmap(icon, mLauncher);
- createItemInfo.spanX = createItemInfo.spanY = 1;
- }
-
- // Don't clip alpha values for the drag outline if we're using the default widget preview
- boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
- (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
-
- // Save the preview for the outline generation, then dim the preview
- outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
- false);
-
- // Start the drag
- mLauncher.lockScreenOrientation();
- mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
- mDragController.startDrag(image, preview, this, createItemInfo,
- DragController.DRAG_ACTION_COPY, previewPadding, scale);
- outline.recycle();
- preview.recycle();
- return true;
- }
-
- @Override
- protected boolean beginDragging(final View v) {
- if (!super.beginDragging(v)) return false;
-
- if (v instanceof PagedViewWidget) {
- if (!beginDraggingWidget((PagedViewWidget) v)) {
- return false;
- }
- } else {
- Log.e(TAG, "Unexpected dragging view: " + v);
- }
-
- // We delay entering spring-loaded mode slightly to make sure the UI
- // thready is free of any work.
- postDelayed(new Runnable() {
- @Override
- public void run() {
- // We don't enter spring-loaded mode if the drag has been cancelled
- if (mLauncher.getDragController().isDragging()) {
- // Go into spring loaded mode (must happen before we startDrag())
- mLauncher.enterSpringLoadedDragMode();
- }
- }
- }, 150);
-
- return true;
- }
-
- /**
- * Clean up after dragging.
- *
- * @param target where the item was dragged to (can be null if the item was flung)
- */
- private void endDragging(View target, boolean isFlingToDelete, boolean success) {
- if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
- !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
- // Exit spring loaded mode if we have not successfully dropped or have not handled the
- // drop in Workspace
- mLauncher.exitSpringLoadedDragModeDelayed(true,
- Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
- mLauncher.unlockScreenOrientation(false);
- } else {
- mLauncher.unlockScreenOrientation(false);
- }
- }
-
- @Override
- public View getContent() {
- if (getChildCount() > 0) {
- return getChildAt(0);
- }
- return null;
- }
-
- @Override
- public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
- mInTransition = true;
- if (toWorkspace) {
- cancelAllTasks(false);
- }
- }
-
- @Override
- public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
- }
-
- @Override
- public void onLauncherTransitionStep(Launcher l, float t) {
- }
-
- @Override
- public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
- mInTransition = false;
- mForceDrawAllChildrenNextFrame = !toWorkspace;
- if (!toWorkspace) {
- loadPreviewsForPage(getNextPage());
- }
- }
-
- @Override
- public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
- boolean success) {
- // Return early and wait for onFlingToDeleteCompleted if this was the result of a fling
- if (isFlingToDelete) return;
-
- endDragging(target, false, success);
-
- // Display an error message if the drag failed due to there not being enough space on the
- // target layout we were dropping on.
- if (!success) {
- boolean showOutOfSpaceMessage = false;
- if (target instanceof Workspace) {
- int currentScreen = mLauncher.getCurrentWorkspaceScreen();
- Workspace workspace = (Workspace) target;
- CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
- ItemInfo itemInfo = (ItemInfo) d.dragInfo;
- if (layout != null) {
- layout.calculateSpans(itemInfo);
- showOutOfSpaceMessage =
- !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
- }
- }
- if (showOutOfSpaceMessage) {
- mLauncher.showOutOfSpaceMessage(false);
- }
-
- d.deferDragViewCleanupPostAnimation = false;
- }
- cleanupWidgetPreloading(success);
- mDraggingWidget = false;
- }
-
- @Override
- public void onFlingToDeleteCompleted() {
- // We just dismiss the drag when we fling, so cleanup here
- endDragging(null, true, true);
- cleanupWidgetPreloading(false);
- mDraggingWidget = false;
- }
-
- @Override
- public boolean supportsFlingToDelete() {
- return true;
- }
-
- @Override
- public boolean supportsAppInfoDropTarget() {
- return true;
- }
-
- @Override
- public boolean supportsDeleteDropTarget() {
- return false;
- }
-
- @Override
- public float getIntrinsicIconScaleFactor() {
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- return (float) grid.allAppsIconSizePx / grid.iconSizePx;
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- cancelAllTasks(true);
- }
-
- @Override
- public void trimMemory() {
- super.trimMemory();
- cancelAllTasks(true);
- }
-
- private void cancelAllTasks(boolean clearCompletedTasks) {
- for (int page = getPageCount() - 1; page >= 0; page--) {
- final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
- if (layout != null) {
- for (int i = 0; i < layout.getChildCount(); i++) {
- ((PagedViewWidget) layout.getChildAt(i)).deletePreview(clearCompletedTasks);
- }
- }
- }
- }
-
-
- public void setContentType(ContentType type) {
- // Widgets appear to be cleared every time you leave, always force invalidate for them
- if (mContentType != type || type == ContentType.Widgets) {
- int page = (mContentType != type) ? 0 : getCurrentPage();
- mContentType = type;
- invalidatePageData(page, true);
- }
- }
-
- public ContentType getContentType() {
- return mContentType;
- }
-
- public void setPageBackgroundsVisible(boolean visible) {
- mPageBackgroundsVisible = visible;
- int childCount = getChildCount();
- for (int i = 0; i < childCount; ++i) {
- Drawable bg = getChildAt(i).getBackground();
- if (bg != null) {
- bg.setAlpha(visible ? 255 : 0);
- }
- }
- }
-
- /*
- * Widgets PagedView implementation
- */
- private void setupPage(PagedViewGridLayout layout) {
- // Note: We force a measure here to get around the fact that when we do layout calculations
- // immediately after syncing, we don't have a proper width.
- int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
-
- Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel_dark);
- if (bg != null) {
- bg.setAlpha(mPageBackgroundsVisible ? 255 : 0);
- layout.setBackground(bg);
- }
- layout.measure(widthSpec, heightSpec);
- }
-
- public void syncWidgetPageItems(final int page, final boolean immediate) {
- int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-
- final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
-
- // Calculate the dimensions of each cell we are giving to each widget
- final ArrayList<Object> items = new ArrayList<Object>();
- int contentWidth = mContentWidth - layout.getPaddingLeft() - layout.getPaddingRight();
- final int cellWidth = contentWidth / mWidgetCountX;
- int contentHeight = mContentHeight - layout.getPaddingTop() - layout.getPaddingBottom();
-
- final int cellHeight = contentHeight / mWidgetCountY;
-
- // Prepare the set of widgets to load previews for in the background
- int offset = page * numItemsPerPage;
- for (int i = offset; i < Math.min(offset + numItemsPerPage, mWidgets.size()); ++i) {
- items.add(mWidgets.get(i));
- }
-
- // Prepopulate the pages with the other widget info, and fill in the previews later
- layout.setColumnCount(layout.getCellCountX());
- for (int i = 0; i < items.size(); ++i) {
- Object rawInfo = items.get(i);
- PendingAddItemInfo createItemInfo = null;
- PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
- R.layout.apps_customize_widget, layout, false);
-
- if (rawInfo instanceof LauncherAppWidgetProviderInfo) {
- // Fill in the widget information
- LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) rawInfo;
- createItemInfo = new PendingAddWidgetInfo(info, null);
-
- widget.applyFromAppWidgetProviderInfo(info, -1, getWidgetPreviewLoader());
- widget.setTag(createItemInfo);
- widget.setShortPressListener(this);
- } else if (rawInfo instanceof ResolveInfo) {
- // Fill in the shortcuts information
- ResolveInfo info = (ResolveInfo) rawInfo;
- createItemInfo = new PendingAddShortcutInfo(info.activityInfo);
- createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
- createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
- info.activityInfo.name);
- widget.applyFromResolveInfo(mPackageManager, info, getWidgetPreviewLoader());
- widget.setTag(createItemInfo);
- }
-
- widget.setOnClickListener(this);
- widget.setOnLongClickListener(this);
- widget.setOnTouchListener(this);
- widget.setOnKeyListener(mKeyListener);
-
- // Layout each widget
- int ix = i % mWidgetCountX;
- int iy = i / mWidgetCountX;
-
- if (ix > 0) {
- View border = widget.findViewById(R.id.left_border);
- border.setVisibility(View.VISIBLE);
- }
- if (ix < mWidgetCountX - 1) {
- View border = widget.findViewById(R.id.right_border);
- border.setVisibility(View.VISIBLE);
- }
-
- GridLayout.LayoutParams lp = new GridLayout.LayoutParams(
- GridLayout.spec(iy, GridLayout.START),
- GridLayout.spec(ix, GridLayout.TOP));
- lp.width = cellWidth;
- lp.height = cellHeight;
- lp.setGravity(Gravity.TOP | Gravity.START);
- layout.addView(widget, lp);
- }
-
- if (immediate && !mInTransition) {
- loadPreviewsForPage(page);
- }
- }
-
- private void loadPreviewsForPage(int page) {
- final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
-
- if (layout != null) {
- for (int i = 0; i < layout.getChildCount(); i++) {
- ((PagedViewWidget) layout.getChildAt(i)).ensurePreview();
- }
- }
- }
-
- @Override
- public void syncPages() {
- disablePagedViewAnimations();
-
- removeAllViews();
- cancelAllTasks(true);
-
- Context context = getContext();
- if (mContentType == ContentType.Widgets) {
- for (int j = 0; j < mNumWidgetPages; ++j) {
- PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
- mWidgetCountY);
- setupPage(layout);
- addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.MATCH_PARENT));
- }
- } else {
- throw new RuntimeException("Invalid ContentType");
- }
-
- enablePagedViewAnimations();
- }
-
- @Override
- public void syncPageItems(int page, boolean immediate) {
- if (mContentType == ContentType.Widgets) {
- syncWidgetPageItems(page, immediate);
- } else {
- Log.e(TAG, "Unexpected ContentType");
- }
- }
-
- // We want our pages to be z-ordered such that the further a page is to the left, the higher
- // it is in the z-order. This is important to insure touch events are handled correctly.
- View getPageAt(int index) {
- return getChildAt(indexToPage(index));
- }
-
- @Override
- protected int indexToPage(int index) {
- return getChildCount() - index - 1;
- }
-
- // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
- @Override
- protected void screenScrolled(int screenCenter) {
- super.screenScrolled(screenCenter);
- enableHwLayersOnVisiblePages();
- }
-
- private void enableHwLayersOnVisiblePages() {
- final int screenCount = getChildCount();
-
- getVisiblePages(mTempVisiblePagesRange);
- int leftScreen = mTempVisiblePagesRange[0];
- int rightScreen = mTempVisiblePagesRange[1];
- int forceDrawScreen = -1;
- if (leftScreen == rightScreen) {
- // make sure we're caching at least two pages always
- if (rightScreen < screenCount - 1) {
- rightScreen++;
- forceDrawScreen = rightScreen;
- } else if (leftScreen > 0) {
- leftScreen--;
- forceDrawScreen = leftScreen;
- }
- } else {
- forceDrawScreen = leftScreen + 1;
- }
-
- for (int i = 0; i < screenCount; i++) {
- final View layout = (View) getPageAt(i);
- if (!(leftScreen <= i && i <= rightScreen &&
- (i == forceDrawScreen || shouldDrawChild(layout)))) {
- layout.setLayerType(LAYER_TYPE_NONE, null);
- }
- }
-
- for (int i = 0; i < screenCount; i++) {
- final View layout = (View) getPageAt(i);
-
- if (leftScreen <= i && i <= rightScreen &&
- (i == forceDrawScreen || shouldDrawChild(layout))) {
- if (layout.getLayerType() != LAYER_TYPE_HARDWARE) {
- layout.setLayerType(LAYER_TYPE_HARDWARE, null);
- }
- }
- }
- }
-
- protected void overScroll(float amount) {
- dampedOverScroll(amount);
- }
-
- /**
- * Used by the parent to get the content width to set the tab bar to
- * @return
- */
- public int getPageContentWidth() {
- return mContentWidth;
- }
-
- @Override
- protected void onPageEndMoving() {
- super.onPageEndMoving();
- mForceDrawAllChildrenNextFrame = true;
- // We reset the save index when we change pages so that it will be recalculated on next
- // rotation
- mSaveInstanceStateItemIndex = -1;
- }
-
- @Override
- protected void onPageBeginMoving() {
- super.onPageBeginMoving();
- if (!mInTransition) {
- getVisiblePages(sTempPosArray);
- for (int i = sTempPosArray[0]; i <= sTempPosArray[1]; i++) {
- loadPreviewsForPage(i);
- }
- }
- }
-
- /*
- * AllAppsView implementation
- */
- public void setup(Launcher launcher, DragController dragController) {
- mLauncher = launcher;
- mDragController = dragController;
- }
-
- /**
- * We should call thise method whenever the core data changes (mWidgets) so that we can
- * appropriately determine when to invalidate the PagedView page data. In cases where the data
- * has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
- * next onMeasure() pass, which will trigger an invalidatePageData() itself.
- */
- private void invalidateOnDataChange() {
- if (!isDataReady()) {
- // The next layout pass will trigger data-ready if both widgets and apps are set, so
- // request a layout to trigger the page data when ready.
- requestLayout();
- } else {
- cancelAllTasks(false);
- invalidatePageData();
- }
- }
-
- public void reset() {
- // If we have reset, then we should not continue to restore the previous state
- mSaveInstanceStateItemIndex = -1;
-
- if (mContentType != ContentType.Widgets) {
- setContentType(ContentType.Widgets);
- }
-
- if (mCurrentPage != 0) {
- invalidatePageData(0);
- }
- }
-
- private AppsCustomizeTabHost getTabHost() {
- return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane);
- }
-
- public void dumpState() {
- // TODO: Dump information related to current list of Applications, Widgets, etc.
- dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
- }
-
- private void dumpAppWidgetProviderInfoList(String tag, String label,
- ArrayList<Object> list) {
- Log.d(tag, label + " size=" + list.size());
- for (Object i: list) {
- if (i instanceof AppWidgetProviderInfo) {
- AppWidgetProviderInfo info = (AppWidgetProviderInfo) i;
- Log.d(tag, " label=\"" + info.label + "\" previewImage=" + info.previewImage
- + " resizeMode=" + info.resizeMode + " configure=" + info.configure
- + " initialLayout=" + info.initialLayout
- + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight);
- } else if (i instanceof ResolveInfo) {
- ResolveInfo info = (ResolveInfo) i;
- Log.d(tag, " label=\"" + info.loadLabel(mPackageManager) + "\" icon="
- + info.icon);
- }
- }
- }
-
- public void surrender() {
- // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we
- // should stop this now.
-
- // Stop all background tasks
- cancelAllTasks(true);
- }
-
- /*
- * We load an extra page on each side to prevent flashes from scrolling and loading of the
- * widget previews in the background with the AsyncTasks.
- */
- final static int sLookBehindPageCount = 2;
- final static int sLookAheadPageCount = 2;
- protected int getAssociatedLowerPageBound(int page) {
- final int count = getChildCount();
- int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
- int windowMinIndex = Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0);
- return windowMinIndex;
- }
- protected int getAssociatedUpperPageBound(int page) {
- final int count = getChildCount();
- int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
- int windowMaxIndex = Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1),
- count - 1);
- return windowMaxIndex;
- }
-
- protected String getCurrentPageDescription() {
- int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
- int stringId = R.string.default_scroll_format;
- int count = 0;
-
- if (mContentType == ContentType.Widgets) {
- stringId = R.string.apps_customize_widgets_scroll_format;
- count = mNumWidgetPages;
- } else {
- throw new RuntimeException("Invalid ContentType");
- }
-
- return String.format(getContext().getString(stringId), page + 1, count);
- }
-}
diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java
deleted file mode 100644
index 5e2f05c..0000000
--- a/src/com/android/launcher3/AppsCustomizeTabHost.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2011 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;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.FrameLayout;
-
-public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable {
- static final String LOG_TAG = "AppsCustomizeTabHost";
-
- private static final String WIDGETS_TAB_TAG = "WIDGETS";
-
- private AppsCustomizePagedView mPagedView;
- private View mContent;
- private boolean mInTransition = false;
-
- private final Rect mInsets = new Rect();
-
- public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- /**
- * Convenience methods to select specific tabs. We want to set the content type immediately
- * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view
- * reflects the new content (but doesn't do the animation and logic associated with changing
- * tabs manually).
- */
- void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) {
- mPagedView.setContentType(type);
- }
-
- @Override
- public void setInsets(Rect insets) {
- mInsets.set(insets);
- LayoutParams flp = (LayoutParams) mContent.getLayoutParams();
- flp.topMargin = insets.top;
- flp.bottomMargin = insets.bottom;
- flp.leftMargin = insets.left;
- flp.rightMargin = insets.right;
- mContent.setLayoutParams(flp);
- }
-
- /**
- * Setup the tab host and create all necessary tabs.
- */
- @Override
- protected void onFinishInflate() {
- mPagedView = (AppsCustomizePagedView) findViewById(R.id.apps_customize_pane_content);
- mContent = findViewById(R.id.content);
- }
-
- public String getContentTag() {
- return getTabTagForContentType(mPagedView.getContentType());
- }
-
- /**
- * Returns the content view used for the launcher transitions.
- */
- public View getContentView() {
- return findViewById(R.id.apps_customize_pane_content);
- }
-
- /**
- * Returns the reveal view used for the launcher transitions.
- */
- public View getRevealView() {
- return findViewById(R.id.fake_page);
- }
-
- /**
- * Returns the page indicators view.
- */
- public View getPageIndicators() {
- return findViewById(R.id.apps_customize_page_indicator);
- }
-
- /**
- * Returns the content type for the specified tab tag.
- */
- public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
- return AppsCustomizePagedView.ContentType.Widgets;
- }
-
- /**
- * Returns the tab tag for a given content type.
- */
- public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
- return WIDGETS_TAB_TAG;
- }
-
- /**
- * Disable focus on anything under this view in the hierarchy if we are not visible.
- */
- @Override
- public int getDescendantFocusability() {
- if (getVisibility() != View.VISIBLE) {
- return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
- }
- return super.getDescendantFocusability();
- }
-
- void reset() {
- // Reset immediately
- mPagedView.reset();
- }
-
- void trimMemory() {
- mPagedView.trimMemory();
- }
-
- public void onWindowVisible() {
- if (getVisibility() == VISIBLE) {
- mContent.setVisibility(VISIBLE);
- // We unload the widget previews when the UI is hidden, so need to reload pages
- // Load the current page synchronously, and the neighboring pages asynchronously
- mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true);
- mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
- }
- }
- @Override
- public ViewGroup getContent() {
- return mPagedView;
- }
-
- public boolean isInTransition() {
- return mInTransition;
- }
-
- /* LauncherTransitionable overrides */
- @Override
- public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
- mPagedView.onLauncherTransitionPrepare(l, animated, toWorkspace);
- mInTransition = true;
-
- if (toWorkspace) {
- // Going from All Apps -> Workspace
- setVisibilityOfSiblingsWithLowerZOrder(VISIBLE);
- } else {
- // Going from Workspace -> All Apps
- mContent.setVisibility(VISIBLE);
-
- // Make sure the current page is loaded (we start loading the side pages after the
- // transition to prevent slowing down the animation)
- // TODO: revisit this
- mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
- }
- }
-
- @Override
- public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
- mPagedView.onLauncherTransitionStart(l, animated, toWorkspace);
- }
-
- @Override
- public void onLauncherTransitionStep(Launcher l, float t) {
- mPagedView.onLauncherTransitionStep(l, t);
- }
-
- @Override
- public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
- mPagedView.onLauncherTransitionEnd(l, animated, toWorkspace);
- mInTransition = false;
-
- if (!toWorkspace) {
- // Make sure adjacent pages are loaded (we wait until after the transition to
- // prevent slowing down the animation)
- mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
-
- // Opening apps, need to announce what page we are on.
- AccessibilityManager am = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- if (am.isEnabled()) {
- // Notify the user when the page changes
- announceForAccessibility(mPagedView.getCurrentPageDescription());
- }
-
- // Going from Workspace -> All Apps
- // NOTE: We should do this at the end since we check visibility state in some of the
- // cling initialization/dismiss code above.
- setVisibilityOfSiblingsWithLowerZOrder(INVISIBLE);
- }
- }
-
- private void setVisibilityOfSiblingsWithLowerZOrder(int visibility) {
- ViewGroup parent = (ViewGroup) getParent();
- if (parent == null) return;
-
- View appsView = ((Launcher) getContext()).getAppsView();
- View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
- final int count = parent.getChildCount();
- if (!isChildrenDrawingOrderEnabled()) {
- for (int i = 0; i < count; i++) {
- final View child = parent.getChildAt(i);
- if (child == this) {
- break;
- } else {
- if (child.getVisibility() == GONE || child == overviewPanel ||
- child == appsView) {
- continue;
- }
- child.setVisibility(visibility);
- }
- }
- } else {
- throw new RuntimeException("Failed; can't get z-order of views");
- }
- }
-}
diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java
index 5b6967c..c8ce397 100644
--- a/src/com/android/launcher3/AppsGridAdapter.java
+++ b/src/com/android/launcher3/AppsGridAdapter.java
@@ -112,6 +112,7 @@
private LayoutInflater mLayoutInflater;
@Thunk AlphabeticalAppsList mApps;
+ private GridLayoutManager mGridLayoutMgr;
private GridSpanSizer mGridSizer;
private GridItemDecoration mItemDecoration;
private View.OnTouchListener mTouchListener;
@@ -135,6 +136,9 @@
mApps = apps;
mAppsPerRow = appsPerRow;
mGridSizer = new GridSpanSizer();
+ mGridLayoutMgr = new GridLayoutManager(context, appsPerRow, GridLayoutManager.VERTICAL,
+ false);
+ mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
mItemDecoration = new GridItemDecoration();
mLayoutInflater = LayoutInflater.from(context);
mTouchListener = touchListener;
@@ -150,6 +154,14 @@
}
/**
+ * Sets the number of apps per row.
+ */
+ public void setNumAppsPerRow(int appsPerRow) {
+ mAppsPerRow = appsPerRow;
+ mGridLayoutMgr.setSpanCount(appsPerRow);
+ }
+
+ /**
* Sets whether we are in RTL mode.
*/
public void setRtl(boolean rtl) {
@@ -167,10 +179,7 @@
* Returns the grid layout manager.
*/
public GridLayoutManager getLayoutManager(Context context) {
- GridLayoutManager layoutMgr = new GridLayoutManager(context, mAppsPerRow,
- GridLayoutManager.VERTICAL, false);
- layoutMgr.setSpanSizeLookup(mGridSizer);
- return layoutMgr;
+ return mGridLayoutMgr;
}
/**
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 63afa30..f4afb95 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -45,7 +45,6 @@
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
@@ -56,6 +55,7 @@
import com.android.launcher3.FolderIcon.FolderRingAnimator;
import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
import java.util.ArrayList;
import java.util.Arrays;
@@ -3025,7 +3025,7 @@
*
* @return True if a vacant cell of the specified dimension was found, false otherwise.
*/
- boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
+ public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 1f0dad2..62aa285 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -42,6 +42,7 @@
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.WidgetsContainerView;
public class DeleteDropTarget extends ButtonDropTarget {
private static int DELETE_ANIMATION_DURATION = 285;
@@ -100,8 +101,9 @@
private boolean isAllAppsApplication(DragSource source, Object info) {
return source.supportsAppInfoDropTarget() && (info instanceof AppInfo);
}
- private boolean isAllAppsWidget(DragSource source, Object info) {
- if (source instanceof AppsCustomizePagedView) {
+
+ private boolean isWidget(DragSource source, Object info) {
+ if (source instanceof WidgetsContainerView) {
if (info instanceof PendingAddItemInfo) {
PendingAddItemInfo addInfo = (PendingAddItemInfo) info;
switch (addInfo.itemType) {
@@ -173,7 +175,7 @@
// If we are dragging an application from AppsCustomize, only show the control if we can
// delete the app (it was downloaded), and rename the string to "uninstall" in such a case.
// Hide the delete target if it is a widget from AppsCustomize.
- if (!willAcceptDrop(info) || isAllAppsWidget(source, info)) {
+ if (!willAcceptDrop(info) || isWidget(source, info)) {
isVisible = false;
}
if (useUninstallLabel) {
@@ -489,13 +491,14 @@
}
public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) {
- final boolean isAllApps = d.dragSource instanceof AppsCustomizePagedView;
+ final boolean isWidgets = d.dragSource instanceof WidgetsContainerView;
+ final boolean isAllapps = d.dragSource instanceof AppsContainerView;
// 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 (isAllApps) {
+ if (isWidgets || isAllapps) {
resetHoverColor();
}
@@ -545,7 +548,7 @@
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 (!isAllApps) {
+ if (!isWidgets || !isAllapps) {
mLauncher.exitSpringLoadedDragMode();
completeDrop(d);
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 331695a..786f2ce 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -106,8 +106,8 @@
public int cellWidthPx;
public int cellHeightPx;
- int iconSizePx;
- int iconTextSizePx;
+ public int iconSizePx;
+ public int iconTextSizePx;
int iconDrawablePaddingPx;
int allAppsIconSizePx;
int allAppsIconTextSizePx;
@@ -423,13 +423,21 @@
allAppsNumCols = Math.max(minEdgeCellCount, Math.min(maxCols, allAppsNumCols));
}
- int appsContainerViewPx = res.getDimensionPixelSize(R.dimen.apps_container_width);
+ int appsContainerViewWidthPx = res.getDimensionPixelSize(R.dimen.apps_container_width);
+ updateAppsViewNumCols(res, appsContainerViewWidthPx);
+ }
+
+ public boolean updateAppsViewNumCols(Resources res, int containerWidth) {
int appsViewLeftMarginPx =
res.getDimensionPixelSize(R.dimen.apps_grid_view_start_margin);
- int availableAppsWidthPx = (appsContainerViewPx > 0) ? appsContainerViewPx :
- availableWidthPx;
- appsViewNumCols = (availableAppsWidthPx - appsViewLeftMarginPx) /
+ int availableAppsWidthPx = (containerWidth > 0) ? containerWidth : availableWidthPx;
+ int numCols = (availableAppsWidthPx - appsViewLeftMarginPx) /
(allAppsCellWidthPx + 2 * allAppsCellPaddingPx);
+ if (numCols != appsViewNumCols) {
+ appsViewNumCols = numCols;
+ return true;
+ }
+ return false;
}
void updateFromConfiguration(Context context, Resources resources, int wPx, int hPx,
@@ -803,64 +811,6 @@
}
}
- // Layout AllApps
- AppsCustomizeTabHost host = (AppsCustomizeTabHost)
- launcher.findViewById(R.id.apps_customize_pane);
- if (host != null) {
- // Center the all apps page indicator
- int pageIndicatorHeight = (int) (pageIndicatorHeightPx * Math.min(1f,
- (allAppsIconSizePx / DynamicGrid.DEFAULT_ICON_SIZE_PX)));
- pageIndicator = host.findViewById(R.id.apps_customize_page_indicator);
- if (pageIndicator != null) {
- LinearLayout.LayoutParams lllp = (LinearLayout.LayoutParams) pageIndicator.getLayoutParams();
- lllp.width = LayoutParams.WRAP_CONTENT;
- lllp.height = pageIndicatorHeight;
- pageIndicator.setLayoutParams(lllp);
- }
-
- AppsCustomizePagedView pagedView = (AppsCustomizePagedView)
- host.findViewById(R.id.apps_customize_pane_content);
-
- FrameLayout fakePageContainer = (FrameLayout)
- host.findViewById(R.id.fake_page_container);
- FrameLayout fakePage = (FrameLayout) host.findViewById(R.id.fake_page);
-
- padding = new Rect();
- if (pagedView != null) {
- // Constrain the dimensions of all apps so that it does not span the full width
- int paddingLR = (availableWidthPx - (allAppsCellWidthPx * allAppsNumCols)) /
- (2 * (allAppsNumCols + 1));
- int paddingTB = (availableHeightPx - (allAppsCellHeightPx * allAppsNumRows)) /
- (2 * (allAppsNumRows + 1));
- paddingLR = Math.min(paddingLR, (int)((paddingLR + paddingTB) * 0.75f));
- paddingTB = Math.min(paddingTB, (int)((paddingLR + paddingTB) * 0.75f));
- int maxAllAppsWidth = (allAppsNumCols * (allAppsCellWidthPx + 2 * paddingLR));
- int gridPaddingLR = (availableWidthPx - maxAllAppsWidth) / 2;
- // Only adjust the side paddings on landscape phones, or tablets
- if ((isTablet() || isLandscape) && gridPaddingLR > (allAppsCellWidthPx / 4)) {
- padding.left = padding.right = gridPaddingLR;
- }
-
- // The icons are centered, so we can't just offset by the page indicator height
- // because the empty space will actually be pageIndicatorHeight + paddingTB
- padding.bottom = Math.max(0, pageIndicatorHeight - paddingTB);
-
- pagedView.setWidgetsPageIndicatorPadding(pageIndicatorHeight);
- fakePage.setBackground(res.getDrawable(R.drawable.quantum_panel));
-
- // Horizontal padding for the whole paged view
- int pagedFixedViewPadding =
- res.getDimensionPixelSize(R.dimen.apps_customize_horizontal_padding);
-
- padding.left += pagedFixedViewPadding;
- padding.right += pagedFixedViewPadding;
-
- pagedView.setPadding(padding.left, padding.top, padding.right, padding.bottom);
- fakePageContainer.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-
- }
- }
-
// Layout the Overview Mode
ViewGroup overviewMode = launcher.getOverviewPanel();
if (overviewMode != null) {
diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java
index 7369eea..2a1346e 100644
--- a/src/com/android/launcher3/DragSource.java
+++ b/src/com/android/launcher3/DragSource.java
@@ -22,9 +22,9 @@
/**
* Interface defining an object that can originate a drag.
- *
*/
public interface DragSource {
+
/**
* @return whether items dragged from this source supports
*/
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index ff02bbb..28e923e 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -32,7 +32,7 @@
import android.graphics.drawable.Drawable;
import android.util.SparseArray;
-class FastBitmapDrawable extends Drawable {
+public class FastBitmapDrawable extends Drawable {
static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() {
@@ -72,7 +72,7 @@
private boolean mPressed = false;
private ObjectAnimator mPressedAnimator;
- FastBitmapDrawable(Bitmap b) {
+ public FastBitmapDrawable(Bitmap b) {
mAlpha = 255;
mBitmap = b;
setBounds(0, 0, b.getWidth(), b.getHeight());
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 1e1d1ee..0eb1fd8 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -69,7 +69,6 @@
* results in CellLayout being measured as UNSPECIFIED, which it does not support.
*/
private static final int MIN_CONTENT_DIMEN = 5;
- private static final boolean ALLOW_FOLDER_SCROLL = true;
static final int STATE_NONE = -1;
static final int STATE_SMALL = 0;
@@ -101,6 +100,8 @@
private final Alarm mReorderAlarm = new Alarm();
private final Alarm mOnExitAlarm = new Alarm();
+ private final Alarm mOnScrollHintAlarm = new Alarm();
+ @Thunk final Alarm mScrollPauseAlarm = new Alarm();
@Thunk final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
@@ -116,7 +117,7 @@
@Thunk FolderIcon mFolderIcon;
- @Thunk FolderContent mContent;
+ @Thunk FolderPagedView mContent;
@Thunk View mContentWrapper;
FolderEditText mFolderName;
@@ -149,11 +150,6 @@
// Folder scrolling
private int mScrollAreaOffset;
- private Alarm mOnScrollHintAlarm;
- @Thunk Alarm mScrollPauseAlarm;
-
- // TODO: Use {@link #mContent} once {@link #ALLOW_FOLDER_SCROLL} is removed.
- @Thunk FolderPagedView mPagedView;
@Thunk int mScrollHintDir = DragController.SCROLL_NONE;
@Thunk int mCurrentScrollDir = DragController.SCROLL_NONE;
@@ -186,18 +182,13 @@
// name is complete, we have something to focus on, thus hiding the cursor and giving
// reliable behavior when clicking the text field (since it will always gain focus on click).
setFocusableInTouchMode(true);
-
- if (ALLOW_FOLDER_SCROLL) {
- mOnScrollHintAlarm = new Alarm();
- mScrollPauseAlarm = new Alarm();
- }
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mContentWrapper = findViewById(R.id.folder_content_wrapper);
- mContent = (FolderContent) findViewById(R.id.folder_content);
+ mContent = (FolderPagedView) findViewById(R.id.folder_content);
mContent.setFolder(this);
mFolderName = (FolderEditText) findViewById(R.id.folder_name);
@@ -211,16 +202,16 @@
mFolderName.setInputType(mFolderName.getInputType() |
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
- mFooter = ALLOW_FOLDER_SCROLL ? findViewById(R.id.folder_footer) : mFolderName;
+ mFooter = findViewById(R.id.folder_footer);
+ updateFooterHeight();
+ }
+
+ public void updateFooterHeight() {
// We find out how tall footer wants to be (it is set to wrap_content), so that
// we can allocate the appropriate amount of space for it.
int measureSpec = MeasureSpec.UNSPECIFIED;
mFooter.measure(measureSpec, measureSpec);
mFooterHeight = mFooter.getMeasuredHeight();
-
- if (ALLOW_FOLDER_SCROLL) {
- mPagedView = (FolderPagedView) mContent;
- }
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@@ -398,8 +389,7 @@
* @return A new UserFolder.
*/
static Folder fromXml(Context context) {
- return (Folder) LayoutInflater.from(context).inflate(
- ALLOW_FOLDER_SCROLL ? R.layout.user_folder_scroll : R.layout.user_folder, null);
+ return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
}
/**
@@ -424,12 +414,10 @@
public void animateOpen() {
if (!(getParent() instanceof DragLayer)) return;
- if (ALLOW_FOLDER_SCROLL) {
- mPagedView.completePendingPageChanges();
- if (!(mDragInProgress && mPagedView.mIsSorted)) {
- // Open on the first page.
- mPagedView.snapToPageImmediately(0);
- }
+ mContent.completePendingPageChanges();
+ if (!(mDragInProgress && mContent.mIsSorted)) {
+ // Open on the first page.
+ mContent.snapToPageImmediately(0);
}
Animator openFolderAnim = null;
@@ -533,10 +521,8 @@
mDragController.forceTouchMove();
}
- if (ALLOW_FOLDER_SCROLL) {
- FolderPagedView pages = (FolderPagedView) mContent;
- pages.verifyVisibleHighResIcons(pages.getNextPage());
- }
+ FolderPagedView pages = (FolderPagedView) mContent;
+ pages.verifyVisibleHighResIcons(pages.getNextPage());
}
public void beginExternalDrag(ShortcutInfo item) {
@@ -544,7 +530,8 @@
mEmptyCellRank = mContent.allocateRankForNewItem(item);
mIsExternalDrag = true;
mDragInProgress = true;
- if (ALLOW_FOLDER_SCROLL && mPagedView.mIsSorted) {
+
+ if (mContent.mIsSorted) {
mScrollPauseAlarm.setOnAlarmListener(null);
mScrollPauseAlarm.cancelAlarm();
mScrollPauseAlarm.setAlarm(SORTED_STICKY_REORDER_DELAY);
@@ -601,11 +588,9 @@
public void onDragEnter(DragObject d) {
mPrevTargetRank = -1;
mOnExitAlarm.cancelAlarm();
- if (ALLOW_FOLDER_SCROLL) {
- // Get the area offset such that the folder only closes if half the drag icon width
- // is outside the folder area
- mScrollAreaOffset = d.dragView.getDragRegionWidth() / 2 - d.xOffset;
- }
+ // Get the area offset such that the folder only closes if half the drag icon width
+ // is outside the folder area
+ mScrollAreaOffset = d.dragView.getDragRegionWidth() / 2 - d.xOffset;
}
OnAlarmListener mReorderAlarmListener = new OnAlarmListener() {
@@ -632,7 +617,7 @@
}
@Thunk void onDragOver(DragObject d, int reorderDelay) {
- if (ALLOW_FOLDER_SCROLL && mScrollPauseAlarm.alarmPending()) {
+ if (mScrollPauseAlarm.alarmPending()) {
return;
}
final float[] r = new float[2];
@@ -645,27 +630,23 @@
mPrevTargetRank = mTargetRank;
}
- if (!ALLOW_FOLDER_SCROLL) {
- return;
- }
-
float x = r[0];
- int currentPage = mPagedView.getNextPage();
+ int currentPage = mContent.getNextPage();
- float cellOverlap = mPagedView.getCurrentCellLayout().getCellWidth()
+ float cellOverlap = mContent.getCurrentCellLayout().getCellWidth()
* ICON_OVERSCROLL_WIDTH_FACTOR;
boolean isOutsideLeftEdge = x < cellOverlap;
boolean isOutsideRightEdge = x > (getWidth() - cellOverlap);
- if (currentPage > 0 && (mPagedView.rtlLayout ? isOutsideRightEdge : isOutsideLeftEdge)) {
+ if (currentPage > 0 && (mContent.rtlLayout ? isOutsideRightEdge : isOutsideLeftEdge)) {
showScrollHint(DragController.SCROLL_LEFT, d);
- } else if (currentPage < (mPagedView.getPageCount() - 1)
- && (mPagedView.rtlLayout ? isOutsideLeftEdge : isOutsideRightEdge)) {
+ } else if (currentPage < (mContent.getPageCount() - 1)
+ && (mContent.rtlLayout ? isOutsideLeftEdge : isOutsideRightEdge)) {
showScrollHint(DragController.SCROLL_RIGHT, d);
} else {
mOnScrollHintAlarm.cancelAlarm();
if (mScrollHintDir != DragController.SCROLL_NONE) {
- mPagedView.clearScrollHint();
+ mContent.clearScrollHint();
mScrollHintDir = DragController.SCROLL_NONE;
}
}
@@ -674,7 +655,7 @@
private void showScrollHint(int direction, DragObject d) {
// Show scroll hint on the right
if (mScrollHintDir != direction) {
- mPagedView.showScrollHint(direction);
+ mContent.showScrollHint(direction);
mScrollHintDir = direction;
}
@@ -714,13 +695,11 @@
}
mReorderAlarm.cancelAlarm();
- if (ALLOW_FOLDER_SCROLL) {
- mOnScrollHintAlarm.cancelAlarm();
- mScrollPauseAlarm.cancelAlarm();
- if (mScrollHintDir != DragController.SCROLL_NONE) {
- mPagedView.clearScrollHint();
- mScrollHintDir = DragController.SCROLL_NONE;
- }
+ mOnScrollHintAlarm.cancelAlarm();
+ mScrollPauseAlarm.cancelAlarm();
+ if (mScrollHintDir != DragController.SCROLL_NONE) {
+ mContent.clearScrollHint();
+ mScrollHintDir = DragController.SCROLL_NONE;
}
}
@@ -1088,21 +1067,19 @@
};
}
- if (ALLOW_FOLDER_SCROLL) {
- // If the icon was dropped while the page was being scrolled, we need to compute
- // the target location again such that the icon is placed of the final page.
- if (!mPagedView.rankOnCurrentPage(mEmptyCellRank)) {
- // Reorder again.
- mTargetRank = getTargetRank(d, null);
+ // If the icon was dropped while the page was being scrolled, we need to compute
+ // the target location again such that the icon is placed of the final page.
+ if (!mContent.rankOnCurrentPage(mEmptyCellRank)) {
+ // Reorder again.
+ mTargetRank = getTargetRank(d, null);
- // Rearrange items immediately.
- mReorderAlarmListener.onAlarm(mReorderAlarm);
+ // Rearrange items immediately.
+ mReorderAlarmListener.onAlarm(mReorderAlarm);
- mOnScrollHintAlarm.cancelAlarm();
- mScrollPauseAlarm.cancelAlarm();
- }
- mPagedView.completePendingPageChanges();
+ mOnScrollHintAlarm.cancelAlarm();
+ mScrollPauseAlarm.cancelAlarm();
}
+ mContent.completePendingPageChanges();
View currentDragView;
ShortcutInfo si = mCurrentDragInfo;
@@ -1252,10 +1229,10 @@
@Override
public void onAlarm(Alarm alarm) {
if (mCurrentScrollDir == DragController.SCROLL_LEFT) {
- mPagedView.scrollLeft();
+ mContent.scrollLeft();
mScrollHintDir = DragController.SCROLL_NONE;
} else if (mCurrentScrollDir == DragController.SCROLL_RIGHT) {
- mPagedView.scrollRight();
+ mContent.scrollRight();
mScrollHintDir = DragController.SCROLL_NONE;
} else {
// This should not happen
@@ -1286,69 +1263,4 @@
onDragOver(mDragObject, 1);
}
}
-
- public static interface FolderContent {
- void setFolder(Folder f);
-
- void removeItem(View v);
-
- boolean isFull();
- int getItemCount();
-
- int getDesiredWidth();
- int getDesiredHeight();
- void setFixedSize(int width, int height);
-
- /**
- * Iterates over all its items in a reading order.
- * @return the view for which the operator returned true.
- */
- View iterateOverItems(ItemOperator op);
- View getLastItem();
-
- String getAccessibilityDescription();
-
- /**
- * Binds items to the layout.
- * @return list of items that could not be bound, probably because we hit the max size limit.
- */
- ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> children);
-
- /**
- * Create space for a new item, and returns the rank for that item.
- * Resizes the content if necessary.
- */
- int allocateRankForNewItem(ShortcutInfo info);
-
- View createAndAddViewForRank(ShortcutInfo item, int rank);
-
- /**
- * Adds the {@param view} to the layout based on {@param rank} and updated the position
- * related attributes. It assumes that {@param item} is already attached to the view.
- */
- void addViewForRank(View view, ShortcutInfo item, int rank);
-
- /**
- * Reorders the items such that the {@param empty} spot moves to {@param target}
- */
- void realTimeReorder(int empty, int target);
-
- /**
- * @return the rank of the cell nearest to the provided pixel position.
- */
- int findNearestArea(int pixelX, int pixelY);
-
- /**
- * Updates position and rank of all the children in the view based.
- * @param list the ordered list of children.
- * @param itemCount if greater than the total children count, empty spaces are left
- * at the end.
- */
- void arrangeChildren(ArrayList<View> list, int itemCount);
-
- /**
- * Sets the focus on the first visible child.
- */
- void setFocusOnFirstChild();
- }
}
diff --git a/src/com/android/launcher3/FolderCellLayout.java b/src/com/android/launcher3/FolderCellLayout.java
deleted file mode 100644
index 8585add..0000000
--- a/src/com/android/launcher3/FolderCellLayout.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/**
- * 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;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.launcher3.Workspace.ItemOperator;
-
-import java.util.ArrayList;
-
-public class FolderCellLayout extends CellLayout implements Folder.FolderContent {
-
- 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[] sTempPosArray = new int[2];
-
- private final FolderKeyEventListener mKeyListener = new FolderKeyEventListener();
- private final LayoutInflater mInflater;
- private final IconCache mIconCache;
-
- private final int mMaxCountX;
- private final int mMaxCountY;
- private final int mMaxNumItems;
-
- // Indicates the last number of items used to set up the grid size
- private int mAllocatedContentSize;
-
- private Folder mFolder;
- private FocusIndicatorView mFocusIndicatorView;
-
- public FolderCellLayout(Context context) {
- this(context, null);
- }
-
- public FolderCellLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public FolderCellLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- mMaxCountX = (int) grid.numColumns;
- mMaxCountY = (int) grid.numRows;
- mMaxNumItems = mMaxCountX * mMaxCountY;
-
- mInflater = LayoutInflater.from(context);
- mIconCache = app.getIconCache();
-
- setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
- getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
- setInvertIfRtl(true);
- }
-
- @Override
- public void setFolder(Folder folder) {
- mFolder = folder;
- mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
- }
-
- /**
- * Sets up the grid size such that {@param count} items can fit in the grid.
- * The grid size is calculated such that countY <= countX and countX = ceil(sqrt(count)) while
- * maintaining the restrictions of {@link #mMaxCountX} & {@link #mMaxCountY}.
- */
- private void setupContentDimensions(int count) {
- mAllocatedContentSize = count;
- int countX = getCountX();
- int countY = getCountY();
- boolean done = false;
-
- while (!done) {
- int oldCountX = countX;
- int oldCountY = countY;
- if (countX * countY < count) {
- // Current grid is too small, expand it
- if ((countX <= countY || countY == mMaxCountY) && countX < mMaxCountX) {
- countX++;
- } else if (countY < mMaxCountY) {
- countY++;
- }
- if (countY == 0) countY++;
- } else if ((countY - 1) * countX >= count && countY >= countX) {
- countY = Math.max(0, countY - 1);
- } else if ((countX - 1) * countY >= count) {
- countX = Math.max(0, countX - 1);
- }
- done = countX == oldCountX && countY == oldCountY;
- }
- setGridSize(countX, countY);
- }
-
- @Override
- public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
- ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
- setupContentDimensions(Math.min(items.size(), mMaxNumItems));
-
- int countX = getCountX();
- int rank = 0;
- for (ShortcutInfo item : items) {
- if (rank >= mMaxNumItems) {
- extra.add(item);
- continue;
- }
-
- item.rank = rank;
- item.cellX = rank % countX;
- item.cellY = rank / countX;
- addNewView(item);
- rank++;
- }
- return extra;
- }
-
- @Override
- public int allocateRankForNewItem(ShortcutInfo info) {
- int rank = getItemCount();
- mFolder.rearrangeChildren(rank + 1);
- return rank;
- }
-
- @Override
- public View createAndAddViewForRank(ShortcutInfo item, int rank) {
- updateItemXY(item, rank);
- return addNewView(item);
- }
-
- @Override
- public void addViewForRank(View view, ShortcutInfo item, int rank) {
- updateItemXY(item, rank);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
- lp.cellX = item.cellX;
- lp.cellY = item.cellY;
- addViewToCellLayout(view, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
- }
-
- @Override
- public void removeItem(View v) {
- removeView(v);
- }
-
- /**
- * Updates the item cellX and cellY position
- */
- private void updateItemXY(ShortcutInfo item, int rank) {
- item.rank = rank;
- int countX = getCountX();
- item.cellX = rank % countX;
- item.cellY = rank / countX;
- }
-
- private View addNewView(ShortcutInfo item) {
- final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
- R.layout.folder_application, getShortcutsAndWidgets(), false);
- textView.applyFromShortcutInfo(item, mIconCache, false);
- textView.setOnClickListener(mFolder);
- textView.setOnLongClickListener(mFolder);
- textView.setOnFocusChangeListener(mFocusIndicatorView);
- textView.setOnKeyListener(mKeyListener);
-
- CellLayout.LayoutParams lp = new CellLayout.LayoutParams(
- item.cellX, item.cellY, item.spanX, item.spanY);
- addViewToCellLayout(textView, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
- return textView;
- }
-
- /**
- * Refer {@link #findNearestArea(int, int, int, int, View, boolean, int[])}
- */
- @Override
- public int findNearestArea(int pixelX, int pixelY) {
- findNearestArea(pixelX, pixelY, 1, 1, null, false, sTempPosArray);
- if (mFolder.isLayoutRtl()) {
- sTempPosArray[0] = getCountX() - sTempPosArray[0] - 1;
- }
-
- // Convert this position to rank.
- return Math.min(mAllocatedContentSize - 1,
- sTempPosArray[1] * getCountX() + sTempPosArray[0]);
- }
-
- @Override
- public boolean isFull() {
- return getItemCount() >= mMaxNumItems;
- }
-
- @Override
- public int getItemCount() {
- return getShortcutsAndWidgets().getChildCount();
- }
-
- @Override
- public void arrangeChildren(ArrayList<View> list, int itemCount) {
- setupContentDimensions(itemCount);
- removeAllViews();
-
- int newX, newY;
- int rank = 0;
- int countX = getCountX();
- for (View v : list) {
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
- newX = rank % countX;
- newY = rank / countX;
- ItemInfo info = (ItemInfo) v.getTag();
- if (info.cellX != newX || info.cellY != newY || info.rank != rank) {
- info.cellX = newX;
- info.cellY = newY;
- info.rank = rank;
- LauncherModel.addOrMoveItemInDatabase(getContext(), info,
- mFolder.mInfo.id, 0, info.cellX, info.cellY);
- }
- lp.cellX = info.cellX;
- lp.cellY = info.cellY;
- rank ++;
- addViewToCellLayout(v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
- }
- }
-
- @Override
- public View iterateOverItems(ItemOperator op) {
- for (int j = 0; j < getCountY(); j++) {
- for (int i = 0; i < getCountX(); i++) {
- View v = getChildAt(i, j);
- if ((v != null) && op.evaluate((ItemInfo) v.getTag(), v, this)) {
- return v;
- }
- }
- }
- return null;
- }
-
- @Override
- public String getAccessibilityDescription() {
- return String.format(getContext().getString(R.string.folder_opened),
- getCountX(), getCountY());
- }
-
- @Override
- public void setFocusOnFirstChild() {
- View firstChild = getChildAt(0, 0);
- if (firstChild != null) {
- firstChild.requestFocus();
- }
- }
-
- @Override
- public View getLastItem() {
- int lastRank = getShortcutsAndWidgets().getChildCount() - 1;
- // count can be zero if the folder is not yet laid out.
- int count = getCountX();
- if (count > 0) {
- return getShortcutsAndWidgets().getChildAt(lastRank % count, lastRank / count);
- } else {
- return getShortcutsAndWidgets().getChildAt(lastRank);
- }
- }
-
- @Override
- public void realTimeReorder(int empty, int target) {
- boolean wrap;
- int startX;
- int endX;
- int startY;
- int delay = 0;
- float delayAmount = START_VIEW_REORDER_DELAY;
-
- int countX = getCountX();
- int emptyX = empty % getCountX();
- int emptyY = empty / countX;
-
- int targetX = target % countX;
- int targetY = target / countX;
-
- if (target > empty) {
- wrap = emptyX == countX - 1;
- startY = wrap ? emptyY + 1 : emptyY;
- for (int y = startY; y <= targetY; y++) {
- startX = y == emptyY ? emptyX + 1 : 0;
- endX = y < targetY ? countX - 1 : targetX;
- for (int x = startX; x <= endX; x++) {
- View v = getChildAt(x,y);
- if (animateChildToPosition(v, emptyX, emptyY,
- REORDER_ANIMATION_DURATION, delay, true, true)) {
- emptyX = x;
- emptyY = y;
- delay += delayAmount;
- delayAmount *= VIEW_REORDER_DELAY_FACTOR;
- }
- }
- }
- } else {
- wrap = emptyX == 0;
- startY = wrap ? emptyY - 1 : emptyY;
- for (int y = startY; y >= targetY; y--) {
- startX = y == emptyY ? emptyX - 1 : countX - 1;
- endX = y > targetY ? 0 : targetX;
- for (int x = startX; x >= endX; x--) {
- View v = getChildAt(x,y);
- if (animateChildToPosition(v, emptyX, emptyY,
- REORDER_ANIMATION_DURATION, delay, true, true)) {
- emptyX = x;
- emptyY = y;
- delay += delayAmount;
- delayAmount *= VIEW_REORDER_DELAY_FACTOR;
- }
- }
- }
- }
- }
-}
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 1c42d25..6174892 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -19,7 +19,6 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
-import android.util.LayoutDirection;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -42,10 +41,15 @@
import java.util.Iterator;
import java.util.Map;
-public class FolderPagedView extends PagedView implements Folder.FolderContent {
+public class FolderPagedView extends PagedView {
private static final String TAG = "FolderPagedView";
+ 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;
@@ -96,34 +100,36 @@
setDataIsReady();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- mMaxCountX = Math.min((int) grid.numColumns, MAX_ITEMS_PER_PAGE);
- mMaxCountY = Math.min((int) grid.numRows, MAX_ITEMS_PER_PAGE);
+ if (ALLOW_FOLDER_SCROLL) {
+ mMaxCountX = Math.min((int) grid.numColumns, MAX_ITEMS_PER_PAGE);
+ mMaxCountY = Math.min((int) grid.numRows, MAX_ITEMS_PER_PAGE);
+ } else {
+ mMaxCountX = (int) grid.numColumns;
+ mMaxCountY = (int) grid.numRows;
+ }
+
mMaxItemsPerPage = mMaxCountX * mMaxCountY;
mInflater = LayoutInflater.from(context);
mIconCache = app.getIconCache();
- rtlLayout = getResources().getConfiguration().getLayoutDirection() == LayoutDirection.RTL;
+ rtlLayout = getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_RTL;
}
- @Override
public void setFolder(Folder folder) {
mFolder = folder;
mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
mKeyListener = new PagedFolderKeyEventListener(folder);
-
- mSortButton = folder.findViewById(R.id.folder_sort);
- mSortButton.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- onSortClicked();
- }
- });
mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
- mSortSwitch = (Switch) folder.findViewById(R.id.folder_sort_switch);
+
+ if (ALLOW_ITEM_SORTING) {
+ // Initialize {@link #mSortSwitch} and {@link #mSortButton}.
+ }
}
+ /**
+ * Called when sort button is clicked.
+ */
private void onSortClicked() {
if (mSortOperationPending) {
return;
@@ -138,9 +144,11 @@
private void setIsSorted(boolean isSorted, boolean saveChanges) {
mIsSorted = isSorted;
- mSortSwitch.setChecked(isSorted);
- mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
- saveChanges ? mFolder.mLauncher : null);
+ if (ALLOW_ITEM_SORTING) {
+ mSortSwitch.setChecked(isSorted);
+ mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
+ saveChanges ? mFolder.mLauncher : null);
+ }
}
/**
@@ -282,26 +290,34 @@
}
}
- @Override
+ /**
+ * Binds items to the layout.
+ * @return list of items that could not be bound, probably because we hit the max size limit.
+ */
public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
- mIsSorted = mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
+ mIsSorted = ALLOW_ITEM_SORTING && mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
ArrayList<View> icons = new ArrayList<View>();
+ ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
+
for (ShortcutInfo item : items) {
- icons.add(createNewView(item));
+ if (!ALLOW_FOLDER_SCROLL && icons.size() >= mMaxItemsPerPage) {
+ extra.add(item);
+ } else {
+ icons.add(createNewView(item));
+ }
}
arrangeChildren(icons, icons.size(), false);
- return new ArrayList<ShortcutInfo>();
+ return extra;
}
/**
* Create space for a new item at the end, and returns the rank for that item.
* Also sets the current page to the last page.
*/
- @Override
public int allocateRankForNewItem(ShortcutInfo info) {
int rank = getItemCount();
ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
- if (mIsSorted) {
+ if (ALLOW_ITEM_SORTING && mIsSorted) {
View tmp = new View(getContext());
tmp.setTag(info);
int index = Collections.binarySearch(views, tmp, new ViewComparator());
@@ -321,14 +337,16 @@
return rank;
}
- @Override
public View createAndAddViewForRank(ShortcutInfo item, int rank) {
View icon = createNewView(item);
addViewForRank(icon, item, rank);
return icon;
}
- @Override
+ /**
+ * Adds the {@param view} to the layout based on {@param rank} and updated the position
+ * related attributes. It assumes that {@param item} is already attached to the view.
+ */
public void addViewForRank(View view, ShortcutInfo item, int rank) {
int pagePos = rank % mMaxItemsPerPage;
int pageNo = rank / mMaxItemsPerPage;
@@ -388,14 +406,12 @@
return page;
}
- @Override
public void setFixedSize(int width, int height) {
for (int i = getChildCount() - 1; i >= 0; i --) {
((CellLayout) getChildAt(i)).setFixedSize(width, height);
}
}
- @Override
public void removeItem(View v) {
for (int i = getChildCount() - 1; i >= 0; i --) {
getPageAt(i).removeView(v);
@@ -412,7 +428,6 @@
* at the end, otherwise it is ignored.
*
*/
- @Override
public void arrangeChildren(ArrayList<View> list, int itemCount) {
arrangeChildren(list, itemCount, true);
}
@@ -488,19 +503,26 @@
setCurrentPage(0);
}
- setIsSorted(isSorted, saveChanges);
+ setEnableOverscroll(getPageCount() > 1);
// Update footer
- if (getPageCount() > 1) {
- mPageIndicator.setVisibility(View.VISIBLE);
- mSortButton.setVisibility(View.VISIBLE);
- mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
- setEnableOverscroll(true);
+ 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 {
- mPageIndicator.setVisibility(View.GONE);
- mSortButton.setVisibility(View.GONE);
- mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
- setEnableOverscroll(false);
+ int indicatorVisibility = mPageIndicator.getVisibility();
+ mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
+ if (indicatorVisibility != mPageIndicator.getVisibility()) {
+ mFolder.updateFooterHeight();
+ }
}
}
@@ -521,7 +543,6 @@
return getPageCount() > 0 ? getPageAt(0).getDesiredHeight() : 0;
}
- @Override
public int getItemCount() {
int lastPageIndex = getChildCount() - 1;
if (lastPageIndex < 0) {
@@ -532,7 +553,9 @@
+ lastPageIndex * mMaxItemsPerPage;
}
- @Override
+ /**
+ * @return the rank of the cell nearest to the provided pixel position.
+ */
public int findNearestArea(int pixelX, int pixelY) {
int pageIndex = getNextPage();
CellLayout page = getPageAt(pageIndex);
@@ -550,12 +573,10 @@
R.drawable.ic_pageindicator_default_folder);
}
- @Override
public boolean isFull() {
- return false;
+ return !ALLOW_FOLDER_SCROLL && getItemCount() >= mMaxItemsPerPage;
}
- @Override
public View getLastItem() {
if (getChildCount() < 1) {
return null;
@@ -569,7 +590,10 @@
}
}
- @Override
+ /**
+ * Iterates over all its items in a reading order.
+ * @return the view for which the operator returned true.
+ */
public View iterateOverItems(ItemOperator op) {
for (int k = 0 ; k < getChildCount(); k++) {
CellLayout page = getPageAt(k);
@@ -585,13 +609,14 @@
return null;
}
- @Override
public String getAccessibilityDescription() {
return String.format(getContext().getString(R.string.folder_opened),
mGridCountX, mGridCountY);
}
- @Override
+ /**
+ * Sets the focus on the first visible child.
+ */
public void setFocusOnFirstChild() {
View firstChild = getCurrentCellLayout().getChildAt(0, 0);
if (firstChild != null) {
@@ -605,7 +630,7 @@
if (mFolder != null) {
mFolder.updateTextViewFocus();
}
- if (mSortOperationPending && getNextPage() == 0) {
+ if (ALLOW_ITEM_SORTING && mSortOperationPending && getNextPage() == 0) {
post(new Runnable() {
@Override
@@ -680,7 +705,9 @@
}
}
- @Override
+ /**
+ * Reorders the items such that the {@param empty} spot moves to {@param target}
+ */
public void realTimeReorder(int empty, int target) {
completePendingPageChanges();
int delay = 0;
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index f4af7f5..f6238da 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -44,6 +44,7 @@
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PackageItemInfo;
import java.util.HashMap;
import java.util.HashSet;
@@ -454,12 +455,13 @@
* Fill in {@param appInfo} with the icon and label for {@param packageName}
*/
public synchronized void getTitleAndIconForApp(
- String packageName, UserHandleCompat user, boolean useLowResIcon, AppInfo appInfoOut) {
+ String packageName, UserHandleCompat user, boolean useLowResIcon,
+ PackageItemInfo infoOut) {
CacheEntry entry = getEntryForPackageLocked(packageName, user, useLowResIcon);
- appInfoOut.iconBitmap = entry.icon;
- appInfoOut.title = entry.title;
- appInfoOut.usingLowResIcon = entry.isLowResIcon;
- appInfoOut.contentDescription = entry.contentDescription;
+ infoOut.iconBitmap = entry.icon;
+ infoOut.title = entry.title;
+ infoOut.usingLowResIcon = entry.isLowResIcon;
+ infoOut.contentDescription = entry.contentDescription;
}
public synchronized Bitmap getDefaultIcon(UserHandleCompat user) {
diff --git a/src/com/android/launcher3/Insettable.java b/src/com/android/launcher3/Insettable.java
index 1d2356c..3b8ef2f 100644
--- a/src/com/android/launcher3/Insettable.java
+++ b/src/com/android/launcher3/Insettable.java
@@ -18,6 +18,10 @@
import android.graphics.Rect;
+/**
+ * Allows the implementing {@link View} to not draw underneath system bars.
+ * e.g., notification bar on top and home key area on the bottom.
+ */
public interface Insettable {
void setInsets(Rect insets);
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index f114de2..f7e0ea4 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -36,7 +36,7 @@
*/
static final String EXTRA_PROFILE = "profile";
- static final int NO_ID = -1;
+ public static final int NO_ID = -1;
/**
* The id in the settings database for this item
@@ -82,7 +82,7 @@
/**
* Indicates the Y cell span.
*/
- int spanY = 1;
+ public int spanY = 1;
/**
* Indicates the minimum X cell span.
@@ -107,21 +107,21 @@
/**
* Title of the item
*/
- CharSequence title;
+ public CharSequence title;
/**
* Content description of the item.
*/
- CharSequence contentDescription;
+ public CharSequence contentDescription;
/**
* The position of the item in a drag-and-drop operation.
*/
- int[] dropPos = null;
+ public int[] dropPos = null;
- UserHandleCompat user;
+ public UserHandleCompat user;
- ItemInfo() {
+ public ItemInfo() {
user = UserHandleCompat.myUserHandle();
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2fa2f4a..3d2a346 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -103,6 +103,8 @@
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.WidgetsContainerView;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -130,11 +132,11 @@
implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener,
LauncherStateTransitionAnimation.Callbacks {
- static final String TAG = "Launcher";
- static final boolean LOGD = false;
+ static final String TAG = "Launcher - MERONG";
+ static final boolean LOGD = true;
static final boolean PROFILE_STARTUP = false;
- static final boolean DEBUG_WIDGETS = false;
+ static final boolean DEBUG_WIDGETS = true;
static final boolean DEBUG_STRICT_MODE = false;
static final boolean DEBUG_RESUME_TIME = false;
static final boolean DEBUG_DUMP_LOG = false;
@@ -264,9 +266,13 @@
private View mAllAppsButton;
private SearchDropTargetBar mSearchDropTargetBar;
+
+ // Main container view for the all apps screen.
@Thunk AppsContainerView mAppsView;
- @Thunk AppsCustomizeTabHost mAppsCustomizeTabHost;
- private AppsCustomizePagedView mAppsCustomizeContent;
+
+ // Main container view for the widget tray screen.
+ private WidgetsContainerView mWidgetsView;
+
private boolean mAutoAdvanceRunning = false;
private AppWidgetHostView mQsb;
@@ -514,6 +520,17 @@
public boolean setLauncherCallbacks(LauncherCallbacks callbacks) {
mLauncherCallbacks = callbacks;
+ mLauncherCallbacks.setLauncherAppsCallback(new Launcher.LauncherAppsCallbacks() {
+ @Override
+ public void onAllAppsBoundsChanged(Rect bounds) {
+ mAppsView.setFixedBounds(Launcher.this, bounds);
+ }
+
+ @Override
+ public void dismissAllApps() {
+ showWorkspace(true);
+ }
+ });
return true;
}
@@ -672,7 +689,7 @@
return mInflater;
}
- boolean isDraggingEnabled() {
+ public boolean isDraggingEnabled() {
// We prevent dragging when we are loading the workspace as it is possible to pick up a view
// that is subsequently removed from the workspace in startBinding().
return !mModel.isLoadingWorkspace();
@@ -1013,15 +1030,9 @@
startTimeCallbacks = System.currentTimeMillis();
}
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.setBulkBind(true);
- }
for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) {
mBindOnResumeCallbacks.get(i).run();
}
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.setBulkBind(false);
- }
mBindOnResumeCallbacks.clear();
if (DEBUG_RESUME_TIME) {
Log.d(TAG, "Time spent processing callbacks in onResume: " +
@@ -1141,6 +1152,19 @@
public void forceExitFullImmersion();
}
+ public interface LauncherAppsCallbacks {
+ /**
+ * Updates launcher to the available space that AllApps can take so as not to overlap with
+ * any other views.
+ */
+ public void onAllAppsBoundsChanged(Rect bounds);
+
+ /**
+ * Called to dismiss all apps if it is showing.
+ */
+ public void dismissAllApps();
+ }
+
public interface LauncherOverlayCallbacks {
/**
* This method indicates whether a call to {@link #enterFullImmersion()} will succeed,
@@ -1213,9 +1237,8 @@
if (mModel.isCurrentCallbacks(this)) {
mModel.stopLoader();
}
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.surrender();
- }
+ //TODO(hyunyoungs): stop the widgets loader when there is a rotation.
+
return Boolean.TRUE;
}
@@ -1336,19 +1359,6 @@
mRestoring = true;
}
- // Restore the AppsCustomize tab
- if (mAppsCustomizeTabHost != null) {
- String curTab = savedState.getString("apps_customize_currentTab");
- if (curTab != null) {
- mAppsCustomizeTabHost.setContentTypeImmediate(
- mAppsCustomizeTabHost.getContentTypeForTabTag(curTab));
- mAppsCustomizeContent.loadAssociatedPages(
- mAppsCustomizeContent.getCurrentPage());
- }
-
- int currentIndex = savedState.getInt("apps_customize_currentIndex");
- mAppsCustomizeContent.restorePageForIndex(currentIndex);
- }
mItemIdToViewId = (HashMap<Integer, Integer>)
savedState.getSerializable(RUNTIME_STATE_VIEW_IDS);
}
@@ -1432,12 +1442,12 @@
// Setup Apps
mAppsView = (AppsContainerView) findViewById(R.id.apps_view);
+ if (mLauncherCallbacks != null && mLauncherCallbacks.overrideAllAppsSearch()) {
+ mAppsView.hideSearchBar();
+ }
// Setup AppsCustomize
- mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane);
- mAppsCustomizeContent = (AppsCustomizePagedView)
- mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
- mAppsCustomizeContent.setup(this, dragController);
+ mWidgetsView = (WidgetsContainerView) findViewById(R.id.widgets_view);
// Setup the drag controller (drop targets have to be added in reverse order in priority)
dragController.setDragScoller(mWorkspace);
@@ -1651,7 +1661,7 @@
// Reset AllApps to its initial state only if we are not in the middle of
// processing a multi-step drop
- if (mAppsView != null && mAppsCustomizeTabHost != null &&
+ if (mAppsView != null && mWidgetsView != null &&
mPendingAddInfo.container == ItemInfo.NO_ID) {
showWorkspace(false);
}
@@ -1735,7 +1745,6 @@
// you're in All Apps and click home to go to the workspace. onWindowVisibilityChanged
// is a more appropriate event to handle
if (mVisible) {
- mAppsCustomizeTabHost.onWindowVisible();
if (!mWorkspaceLoading) {
final ViewTreeObserver observer = mWorkspace.getViewTreeObserver();
// We want to let Launcher draw itself at least once before we force it to build
@@ -1839,7 +1848,7 @@
launcherInfo.hostView = null;
}
- void showOutOfSpaceMessage(boolean isHotseatLayout) {
+ public void showOutOfSpaceMessage(boolean isHotseatLayout) {
int strId = (isHotseatLayout ? R.string.hotseat_out_of_space : R.string.out_of_space);
Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show();
}
@@ -1852,8 +1861,8 @@
return mAppsView;
}
- public AppsCustomizeTabHost getWidgetsView() {
- return mAppsCustomizeTabHost;
+ public WidgetsContainerView getWidgetsView() {
+ return mWidgetsView;
}
public Workspace getWorkspace() {
@@ -1946,9 +1955,9 @@
mAppsView.scrollToTop();
}
- // Reset the apps customize page
- if (!alreadyOnHome && mAppsCustomizeTabHost != null) {
- mAppsCustomizeTabHost.reset();
+ // Reset the widgets view
+ if (!alreadyOnHome && mWidgetsView != null) {
+ mWidgetsView.scrollToTop();
}
if (mLauncherCallbacks != null) {
@@ -2003,16 +2012,8 @@
outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id);
}
- // Save the current AppsCustomize tab
- if (mAppsCustomizeTabHost != null) {
- AppsCustomizePagedView.ContentType type = mAppsCustomizeContent.getContentType();
- String currentTabTag = mAppsCustomizeTabHost.getTabTagForContentType(type);
- if (currentTabTag != null) {
- outState.putString("apps_customize_currentTab", currentTabTag);
- }
- int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex();
- outState.putInt("apps_customize_currentIndex", currentIndex);
- }
+ // Save the current widgets tray?
+ // TODO(hyunyoungs)
outState.putSerializable(RUNTIME_STATE_VIEW_IDS, mItemIdToViewId);
if (mLauncherCallbacks != null) {
@@ -2613,9 +2614,6 @@
} else {
showAppsView(true /* animated */, false /* resetListToTop */);
}
- if (mLauncherCallbacks != null) {
- mLauncherCallbacks.onClickAllAppsButton(v);
- }
}
private void showBrokenAppInstallDialog(final String packageName,
@@ -3276,9 +3274,7 @@
SQLiteDatabase.releaseMemory();
// This clears all widget bitmaps from the widget tray
- if (mAppsCustomizeTabHost != null) {
- mAppsCustomizeTabHost.trimMemory();
- }
+ // TODO(hyunyoungs)
}
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onTrimMemory(level);
@@ -3298,7 +3294,9 @@
}
void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
- if (mState != State.WORKSPACE || mWorkspace.getState() != Workspace.State.NORMAL) {
+ boolean changed = mState != State.WORKSPACE ||
+ mWorkspace.getState() != Workspace.State.NORMAL;
+ if (changed) {
boolean wasInSpringLoadedMode = (mState != State.WORKSPACE);
mWorkspace.setVisibility(View.VISIBLE);
mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.NORMAL,
@@ -3323,11 +3321,13 @@
mUserPresent = true;
updateAutoAdvanceState();
- // Send an accessibility event to announce the context change
- getWindow().getDecorView()
- .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ if (changed) {
+ // Send an accessibility event to announce the context change
+ getWindow().getDecorView()
+ .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- onWorkspaceShown(animated);
+ onWorkspaceShown(animated);
+ }
}
void showOverviewMode(boolean animated) {
@@ -3355,15 +3355,16 @@
* Shows the widgets view.
*/
void showWidgetsView(boolean animated, boolean resetPageToZero) {
+ Log.d(TAG, "showWidgetsView:" + animated + " resetPageToZero:" + resetPageToZero);
if (resetPageToZero) {
- mAppsCustomizeTabHost.reset();
+ mWidgetsView.scrollToTop();
}
showAppsOrWidgets(animated, State.WIDGETS);
- mAppsCustomizeTabHost.post(new Runnable() {
+
+ mWidgetsView.post(new Runnable() {
@Override
public void run() {
- // We post this in-case the all apps view isn't yet constructed.
- mAppsCustomizeTabHost.requestFocus();
+ mWidgetsView.requestFocus();
}
});
}
@@ -3377,6 +3378,9 @@
if (toState == State.APPS) {
mStateTransitionAnimation.startAnimationToAllApps(animated);
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onAllAppsShown();
+ }
} else {
mStateTransitionAnimation.startAnimationToWidgets(animated);
}
@@ -3394,7 +3398,9 @@
.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
- void enterSpringLoadedDragMode() {
+ public void enterSpringLoadedDragMode() {
+ Log.d(TAG, String.format("enterSpringLoadedDragMode [mState=%s",
+ mState.name()));
if (mState == State.WORKSPACE || mState == State.APPS_SPRING_LOADED ||
mState == State.WIDGETS_SPRING_LOADED) {
return;
@@ -3405,7 +3411,7 @@
mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED;
}
- void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay,
+ public void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay,
final Runnable onCompleteRunnable) {
if (mState != State.APPS_SPRING_LOADED && mState != State.WIDGETS_SPRING_LOADED) return;
@@ -3413,10 +3419,12 @@
@Override
public void run() {
if (successfulDrop) {
+ // TODO(hyunyoungs): verify if this hack is still needed, if not, delete.
+ //
// Before we show workspace, hide all apps again because
// exitSpringLoadedDragMode made it visible. This is a bit hacky; we should
// clean up our state transition functions
- mAppsCustomizeTabHost.setVisibility(View.GONE);
+ mWidgetsView.setVisibility(View.GONE);
showWorkspace(true, onCompleteRunnable);
} else {
exitSpringLoadedDragMode();
@@ -3918,8 +3926,8 @@
pendingInfo.spanY = item.spanY;
pendingInfo.minSpanX = item.minSpanX;
pendingInfo.minSpanY = item.minSpanY;
- Bundle options =
- AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
+ Bundle options = null;
+ // AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
@@ -4122,9 +4130,9 @@
if (mAppsView != null) {
mAppsView.setApps(apps);
}
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.onPackagesUpdated(
- LauncherModel.getSortedWidgetsAndShortcuts(this, false /* refresh */));
+ if (mWidgetsView != null) {
+ mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false),
+ getPackageManager());
}
if (mLauncherCallbacks != null) {
mLauncherCallbacks.bindAllApplications(apps);
@@ -4276,15 +4284,16 @@
mWidgetsAndShortcuts = null;
}
};
+
public void bindPackagesUpdated(final ArrayList<Object> widgetsAndShortcuts) {
if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) {
mWidgetsAndShortcuts = widgetsAndShortcuts;
return;
}
- // Update the widgets pane
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.onPackagesUpdated(widgetsAndShortcuts);
+ if (mWidgetsView != null) {
+ mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false),
+ getPackageManager());
}
}
@@ -4577,10 +4586,8 @@
Log.d(TAG, "mSavedInstanceState=" + mSavedInstanceState);
Log.d(TAG, "sFolders.size=" + sFolders.size());
mModel.dumpState();
+ // TODO(hyunyoungs): add mWidgetsView.dumpState(); or mWidgetsModel.dumpState();
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.dumpState();
- }
Log.d(TAG, "END launcher3 dump state");
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 2a08b81..3bd3850 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -141,7 +141,7 @@
return mModel;
}
- LauncherAccessibilityDelegate getAccessibilityDelegate() {
+ public LauncherAccessibilityDelegate getAccessibilityDelegate() {
return mAccessibilityDelegate;
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index aeef0da..bb4580c 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -16,10 +16,10 @@
public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo {
public boolean isCustomWidget = false;
- int spanX = -1;
- int spanY = -1;
- int minSpanX = -1;
- int minSpanY = -1;
+ public int spanX = -1;
+ public int spanY = -1;
+ public int minSpanX = -1;
+ public int minSpanY = -1;
public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context,
AppWidgetProviderInfo info) {
@@ -78,10 +78,11 @@
return super.loadIcon(context, cache.getFullResIconDpi());
}
- public String toString() {
+ public String toString(PackageManager pm) {
if (isCustomWidget) {
- return "LauncherAppWidgetProviderInfo(" + provider + ")";
+ return "WidgetProviderInfo(" + provider + ")";
}
- return super.toString();
+ return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s span(%d, %d) minSpan(%d, %d)",
+ provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm), spanX, spanY, minSpanX, minSpanY);
}
}
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index d8128d6..2fee81c 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -50,6 +50,7 @@
public void onLauncherProviderChange();
public void finishBindingItems(final boolean upgradePath);
public void onClickAllAppsButton(View v);
+ public void onAllAppsShown();
public void bindAllApplications(ArrayList<AppInfo> apps);
public void onClickFolderIcon(View v);
public void onClickAppShortcut(View v);
@@ -87,6 +88,7 @@
public ComponentName getWallpaperPickerComponent();
public boolean overrideWallpaperDimensions();
public boolean isLauncherPreinstalled();
+ public boolean overrideAllAppsSearch();
/**
* Returning true will immediately result in a call to {@link #setLauncherOverlayView(ViewGroup,
@@ -106,4 +108,12 @@
public Launcher.LauncherOverlay setLauncherOverlayView(InsettableFrameLayout container,
Launcher.LauncherOverlayCallbacks callbacks);
+ /**
+ * Sets the callbacks to allow any extensions to callback to the launcher.
+ *
+ * @param callbacks A set of callbacks to the Launcher, is actually a LauncherAppsCallback, but
+ * for implementation purposes is passed around as an object.
+ */
+ public void setLauncherAppsCallback(Object callbacks);
+
}
diff --git a/src/com/android/launcher3/LauncherExtension.java b/src/com/android/launcher3/LauncherExtension.java
index fe9bd6c..e4fdbbc 100644
--- a/src/com/android/launcher3/LauncherExtension.java
+++ b/src/com/android/launcher3/LauncherExtension.java
@@ -124,6 +124,10 @@
}
@Override
+ public void onAllAppsShown() {
+ }
+
+ @Override
public void bindAllApplications(ArrayList<AppInfo> apps) {
}
@@ -246,6 +250,11 @@
}
@Override
+ public boolean overrideAllAppsSearch() {
+ return false;
+ }
+
+ @Override
public boolean isLauncherPreinstalled() {
return false;
}
@@ -265,6 +274,11 @@
return mLauncherOverlay;
}
+ @Override
+ public void setLauncherAppsCallback(Object callbacks) {
+ // Do nothing
+ }
+
class LauncherExtensionOverlay implements LauncherOverlay {
LauncherOverlayCallbacks mLauncherOverlayCallbacks;
ViewGroup mOverlayView;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 1f36331..98ba09b 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -3628,7 +3628,7 @@
private final HashMap<Object, String> mLabelCache;
private final Collator mCollator;
- WidgetAndShortcutNameComparator(Context context) {
+ public WidgetAndShortcutNameComparator(Context context) {
mManager = AppWidgetManagerCompat.getInstance(context);
mPackageManager = context.getPackageManager();
mLabelCache = new HashMap<Object, String>();
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index d657cb5..111de40 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -22,7 +22,7 @@
/**
* Settings related utilities.
*/
-class LauncherSettings {
+public class LauncherSettings {
/** Columns required on table staht will be subject to backup and restore. */
static interface ChangeLogColumns extends BaseColumns {
/**
@@ -121,7 +121,7 @@
/**
* Favorites.
*/
- static final class Favorites implements BaseLauncherColumns {
+ public static final class Favorites implements BaseLauncherColumns {
/**
* The content:// style URL for this table
*/
@@ -217,12 +217,12 @@
/**
* The favorite is a widget
*/
- static final int ITEM_TYPE_APPWIDGET = 4;
+ public static final int ITEM_TYPE_APPWIDGET = 4;
/**
* The favorite is a custom widget provided by the launcher
*/
- static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5;
+ public static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5;
/**
* The favorite is a clock
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index eacf341..57bd5b2 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -23,6 +23,7 @@
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.content.res.Resources;
+import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
@@ -30,6 +31,7 @@
import android.view.animation.DecelerateInterpolator;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.WidgetsContainerView;
import java.util.HashMap;
@@ -172,27 +174,19 @@
}
};
startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, toView, toView.getContentView(),
- toView.getRevealView(), null, animated, cb);
+ toView.getRevealView(), animated, false /* hideSearchBar */, cb);
}
/**
* Starts an animation to the widgets view.
*/
public void startAnimationToWidgets(final boolean animated) {
- final AppsCustomizeTabHost toView = mLauncher.getWidgetsView();
+ final WidgetsContainerView toView = mLauncher.getWidgetsView();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
@Override
public void onRevealViewVisible(View revealView, View contentView,
View allAppsButtonView) {
- // Hide the real page background, and swap in the fake one
- ((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(false);
- revealView.setBackground(
- mLauncher.getResources().getDrawable(R.drawable.quantum_panel_dark));
- }
- @Override
- public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
- // Show the real page background
- ((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(true);
+ revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark));
}
@Override
public float getMaterialRevealViewFinalAlpha(View revealView) {
@@ -204,7 +198,7 @@
}
};
startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, toView, toView.getContentView(),
- toView.getRevealView(), toView.getPageIndicators(), animated, cb);
+ toView.getRevealView(), animated, true /* hideSearchBar */, cb);
}
/**
@@ -232,8 +226,8 @@
* Creates and starts a new animation to a particular overlay view.
*/
private void startAnimationToOverlay(final Workspace.State toWorkspaceState, final View toView,
- final View contentView, final View revealView, final View pageIndicatorsView,
- final boolean animated, final PrivateTransitionCallbacks pCb) {
+ final View contentView, final View revealView, final boolean animated,
+ final boolean hideSearchBar, final PrivateTransitionCallbacks pCb) {
final Resources res = mLauncher.getResources();
final boolean material = Utilities.isLmpOrAbove();
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
@@ -299,15 +293,6 @@
layerViews.put(revealView, BUILD_AND_SET_LAYER);
mStateAnimation.play(panelAlphaAndDrift);
- // Setup the animation for the page indicators
- if (pageIndicatorsView != null) {
- pageIndicatorsView.setAlpha(0.01f);
- ObjectAnimator indicatorsAlpha =
- ObjectAnimator.ofFloat(pageIndicatorsView, "alpha", 1f);
- indicatorsAlpha.setDuration(revealDuration);
- mStateAnimation.play(indicatorsAlpha);
- }
-
// Setup the animation for the content view
contentView.setVisibility(View.VISIBLE);
contentView.setAlpha(0f);
@@ -360,8 +345,9 @@
}
}
- // Hide the search bar
- mCb.onStateTransitionHideSearchBar();
+ if (hideSearchBar) {
+ mCb.onStateTransitionHideSearchBar();
+ }
// This can hold unnecessary references to views.
mStateAnimation = null;
@@ -420,8 +406,9 @@
// Show the content view
contentView.setVisibility(View.VISIBLE);
- // Hide the search bar
- mCb.onStateTransitionHideSearchBar();
+ if (hideSearchBar) {
+ mCb.onStateTransitionHideSearchBar();
+ }
dispatchOnLauncherTransitionPrepare(fromView, animated, false);
dispatchOnLauncherTransitionStart(fromView, animated, false);
@@ -490,8 +477,7 @@
}
};
startAnimationToWorkspaceFromOverlay(toWorkspaceState, appsView, appsView.getContentView(),
- appsView.getRevealView(), null /* pageIndicatorsView */, animated,
- onCompleteRunnable, cb);
+ appsView.getRevealView(), animated, onCompleteRunnable, cb);
}
/**
@@ -500,45 +486,9 @@
private void startAnimationToWorkspaceFromWidgets(final Launcher.State fromState,
final Workspace.State toWorkspaceState, final boolean animated,
final Runnable onCompleteRunnable) {
- AppsCustomizeTabHost widgetsView = mLauncher.getWidgetsView();
+ WidgetsContainerView widgetsView = mLauncher.getWidgetsView();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
@Override
- public void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {
- AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
-
- // Hide the real page background, and swap in the fake one
- pagedView.stopScrolling();
- pagedView.setPageBackgroundsVisible(false);
- revealView.setBackground(
- mLauncher.getResources().getDrawable(R.drawable.quantum_panel_dark));
-
- // Hide the side pages of the Widget tray to avoid some ugly edge cases
- final View currentPage = pagedView.getPageAt(pagedView.getNextPage());
- int count = pagedView.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = pagedView.getChildAt(i);
- if (child != currentPage) {
- child.setVisibility(View.INVISIBLE);
- }
- }
- }
- @Override
- public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
- AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
-
- // Show the real page background and force-update the page
- pagedView.setPageBackgroundsVisible(true);
- pagedView.setCurrentPage(pagedView.getNextPage());
- pagedView.updateCurrentPageScroll();
-
- // Unhide the side pages
- int count = pagedView.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = pagedView.getChildAt(i);
- child.setVisibility(View.VISIBLE);
- }
- }
- @Override
public float getMaterialRevealViewFinalYDrift(View revealView) {
return revealView.getMeasuredHeight() / 2;
}
@@ -558,8 +508,8 @@
}
};
startAnimationToWorkspaceFromOverlay(toWorkspaceState, widgetsView,
- widgetsView.getContentView(), widgetsView.getRevealView(),
- widgetsView.getPageIndicators(), animated, onCompleteRunnable, cb);
+ widgetsView.getContentView(), widgetsView.getRevealView(), animated,
+ onCompleteRunnable, cb);
}
/**
@@ -567,8 +517,8 @@
*/
private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState,
final View fromView, final View contentView, final View revealView,
- final View pageIndicatorsView, final boolean animated,
- final Runnable onCompleteRunnable, final PrivateTransitionCallbacks pCb) {
+ final boolean animated, final Runnable onCompleteRunnable,
+ final PrivateTransitionCallbacks pCb) {
final Resources res = mLauncher.getResources();
final boolean material = Utilities.isLmpOrAbove();
final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
@@ -673,16 +623,6 @@
itemsAlpha.setInterpolator(decelerateInterpolator);
mStateAnimation.play(itemsAlpha);
- // Setup the page indicators animation
- if (pageIndicatorsView != null) {
- pageIndicatorsView.setAlpha(1f);
- ObjectAnimator indicatorsAlpha =
- LauncherAnimUtils.ofFloat(pageIndicatorsView, "alpha", 0f);
- indicatorsAlpha.setDuration(revealDuration);
- indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
- mStateAnimation.play(indicatorsAlpha);
- }
-
if (material) {
// Animate the all apps button
float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
diff --git a/src/com/android/launcher3/PagedViewGridLayout.java b/src/com/android/launcher3/PagedViewGridLayout.java
deleted file mode 100644
index f69fa56..0000000
--- a/src/com/android/launcher3/PagedViewGridLayout.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2011 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;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.GridLayout;
-
-/**
- * The grid based layout used strictly for the widget/wallpaper tab of the AppsCustomize pane
- */
-public class PagedViewGridLayout extends GridLayout implements Page {
- static final String TAG = "PagedViewGridLayout";
-
- private int mCellCountX;
- private int mCellCountY;
- private Runnable mOnLayoutListener;
-
- public PagedViewGridLayout(Context context, int cellCountX, int cellCountY) {
- super(context, null, 0);
- mCellCountX = cellCountX;
- mCellCountY = cellCountY;
- }
-
- int getCellCountX() {
- return mCellCountX;
- }
-
- int getCellCountY() {
- return mCellCountY;
- }
-
- /**
- * Clears all the key listeners for the individual widgets.
- */
- public void resetChildrenOnKeyListeners() {
- int childCount = getChildCount();
- for (int j = 0; j < childCount; ++j) {
- getChildAt(j).setOnKeyListener(null);
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mOnLayoutListener = null;
- }
-
- public void setOnLayoutListener(Runnable r) {
- mOnLayoutListener = r;
- }
-
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (mOnLayoutListener != null) {
- mOnLayoutListener.run();
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- boolean result = super.onTouchEvent(event);
- int count = getPageChildCount();
- if (count > 0) {
- // We only intercept the touch if we are tapping in empty space after the final row
- View child = getChildOnPageAt(count - 1);
- int bottom = child.getBottom();
- result = result || (event.getY() < bottom);
- }
- return result;
- }
-
- @Override
- public void removeAllViewsOnPage() {
- removeAllViews();
- mOnLayoutListener = null;
- setLayerType(LAYER_TYPE_NONE, null);
- }
-
- @Override
- public void removeViewOnPageAt(int index) {
- removeViewAt(index);
- }
-
- @Override
- public int getPageChildCount() {
- return getChildCount();
- }
-
- @Override
- public View getChildOnPageAt(int i) {
- return getChildAt(i);
- }
-
- @Override
- public int indexOfChildOnPage(View v) {
- return indexOfChild(v);
- }
-
- public static class LayoutParams extends FrameLayout.LayoutParams {
- public LayoutParams(int width, int height) {
- super(width, height);
- }
- }
-}
diff --git a/src/com/android/launcher3/PagedViewWithDraggableItems.java b/src/com/android/launcher3/PagedViewWithDraggableItems.java
deleted file mode 100644
index f0743cf..0000000
--- a/src/com/android/launcher3/PagedViewWithDraggableItems.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2010 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;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-
-/* Class that does most of the work of enabling dragging items out of a PagedView by performing a
- * vertical drag. Used by both CustomizePagedView and AllAppsPagedView.
- * Subclasses must do the following:
- * * call setDragSlopeThreshold after making an instance of the PagedViewWithDraggableItems
- * * call child.setOnLongClickListener(this) and child.setOnTouchListener(this) on all children
- * (good place to do it is in syncPageItems)
- * * override beginDragging(View) (but be careful to call super.beginDragging(View)
- *
- */
-public abstract class PagedViewWithDraggableItems extends PagedView
- implements View.OnLongClickListener, View.OnTouchListener {
- private View mLastTouchedItem;
- private boolean mIsDragging;
- private boolean mIsDragEnabled;
- private float mDragSlopeThreshold;
- private Launcher mLauncher;
-
- public PagedViewWithDraggableItems(Context context) {
- this(context, null);
- }
-
- public PagedViewWithDraggableItems(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mLauncher = (Launcher) context;
- }
-
- protected boolean beginDragging(View v) {
- boolean wasDragging = mIsDragging;
- mIsDragging = true;
- return !wasDragging;
- }
-
- protected void cancelDragging() {
- mIsDragging = false;
- mLastTouchedItem = null;
- mIsDragEnabled = false;
- }
-
- private void handleTouchEvent(MotionEvent ev) {
- final int action = ev.getAction();
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- cancelDragging();
- mIsDragEnabled = true;
- break;
- case MotionEvent.ACTION_MOVE:
- if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging && mIsDragEnabled) {
- determineDraggingStart(ev);
- }
- break;
- }
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- handleTouchEvent(ev);
- return super.onInterceptTouchEvent(ev);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- handleTouchEvent(ev);
- return super.onTouchEvent(ev);
- }
-
- public void trimMemory() {
- mLastTouchedItem = null;
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- mLastTouchedItem = v;
- mIsDragEnabled = true;
- return false;
- }
-
- @Override
- public boolean onLongClick(View v) {
- // Return early if this is not initiated from a touch
- if (!v.isInTouchMode()) return false;
- // Return early if we are still animating the pages
- if (mNextPage != INVALID_PAGE) return false;
- // When we have exited all apps or are in transition, disregard long clicks
- if (!mLauncher.isWidgetsViewVisible() ||
- mLauncher.getWorkspace().isSwitchingState()) return false;
- // Return if global dragging is not enabled
- if (!mLauncher.isDraggingEnabled()) return false;
-
- return beginDragging(v);
- }
-
- /*
- * Determines if we should change the touch state to start scrolling after the
- * user moves their touch point too far.
- */
- protected void determineScrollingStart(MotionEvent ev) {
- if (!mIsDragging) super.determineScrollingStart(ev);
- }
-
- /*
- * Determines if we should change the touch state to start dragging after the
- * user moves their touch point far enough.
- */
- protected void determineDraggingStart(MotionEvent ev) {
- /*
- * Locally do absolute value. mLastMotionX is set to the y value
- * of the down event.
- */
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- final float x = ev.getX(pointerIndex);
- final float y = ev.getY(pointerIndex);
- final int xDiff = (int) Math.abs(x - mLastMotionX);
- final int yDiff = (int) Math.abs(y - mLastMotionY);
-
- final int touchSlop = mTouchSlop;
- boolean yMoved = yDiff > touchSlop;
- boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold;
-
- if (isUpwardMotion && yMoved && mLastTouchedItem != null) {
- // Drag if the user moved far enough along the Y axis
- beginDragging(mLastTouchedItem);
-
- // Cancel any pending long press
- if (mAllowLongPress) {
- mAllowLongPress = false;
- // Try canceling the long press. It could also have been scheduled
- // by a distant descendant, so use the mAllowLongPress flag to block
- // everything
- final View currentPage = getPageAt(mCurrentPage);
- if (currentPage != null) {
- currentPage.cancelLongPress();
- }
- }
- }
- }
-
- public void setDragSlopeThreshold(float dragSlopeThreshold) {
- mDragSlopeThreshold = dragSlopeThreshold;
- }
-
- @Override
- protected void onDetachedFromWindow() {
- cancelDragging();
- super.onDetachedFromWindow();
- }
-}
diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java
index ac54a26..1aaf85b 100644
--- a/src/com/android/launcher3/PendingAddItemInfo.java
+++ b/src/com/android/launcher3/PendingAddItemInfo.java
@@ -16,93 +16,17 @@
package com.android.launcher3;
-import android.appwidget.AppWidgetHostView;
import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
-import android.os.Bundle;
-import android.os.Parcelable;
/**
- * We pass this object with a drag from the customization tray
+ * Meta data that is used for deferred binding.
+ * e.g., this object is used to pass information on dragable targets when they are dropped onto
+ * the workspace from another container.
*/
-class PendingAddItemInfo extends ItemInfo {
+public class PendingAddItemInfo extends ItemInfo {
+
/**
* The component that will be created.
*/
- ComponentName componentName;
-}
-
-class PendingAddShortcutInfo extends PendingAddItemInfo {
-
- ActivityInfo shortcutActivityInfo;
-
- public PendingAddShortcutInfo(ActivityInfo activityInfo) {
- shortcutActivityInfo = activityInfo;
- }
-
- @Override
- public String toString() {
- return "Shortcut: " + shortcutActivityInfo.packageName;
- }
-}
-
-class PendingAddWidgetInfo extends PendingAddItemInfo {
- int minWidth;
- int minHeight;
- int minResizeWidth;
- int minResizeHeight;
- int previewImage;
- int icon;
- LauncherAppWidgetProviderInfo info;
- AppWidgetHostView boundWidget;
- Bundle bindOptions = null;
-
- public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, Parcelable data) {
- if (i.isCustomWidget) {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
- } else {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
- }
- this.info = i;
- componentName = i.provider;
- minWidth = i.minWidth;
- minHeight = i.minHeight;
- minResizeWidth = i.minResizeWidth;
- minResizeHeight = i.minResizeHeight;
- previewImage = i.previewImage;
- icon = i.icon;
-
- spanX = i.spanX;
- spanY = i.spanY;
- minSpanX = i.minSpanX;
- minSpanY = i.minSpanY;
- }
-
- public boolean isCustomWidget() {
- return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
- }
-
- // Copy constructor
- public PendingAddWidgetInfo(PendingAddWidgetInfo copy) {
- minWidth = copy.minWidth;
- minHeight = copy.minHeight;
- minResizeWidth = copy.minResizeWidth;
- minResizeHeight = copy.minResizeHeight;
- previewImage = copy.previewImage;
- icon = copy.icon;
- info = copy.info;
- boundWidget = copy.boundWidget;
- componentName = copy.componentName;
- itemType = copy.itemType;
- spanX = copy.spanX;
- spanY = copy.spanY;
- minSpanX = copy.minSpanX;
- minSpanY = copy.minSpanY;
- bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone();
- }
-
- @Override
- public String toString() {
- return "Widget: " + componentName.toShortString();
- }
+ public ComponentName componentName;
}
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 1043e2e..5c3ed92 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -32,6 +32,7 @@
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.WidgetCell;
import java.lang.ref.WeakReference;
import java.util.Collections;
@@ -45,6 +46,7 @@
public class WidgetPreviewLoader {
private static final String TAG = "WidgetPreviewLoader";
+ private static final boolean DEBUG = false;
private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f;
@@ -78,7 +80,7 @@
* @return a request id which can be used to cancel the request.
*/
public PreviewLoadRequest getPreview(final Object o, int previewWidth, int previewHeight,
- PagedViewWidget caller, Bitmap[] immediateResult) {
+ WidgetCell caller, Bitmap[] immediateResult) {
String size = previewWidth + "x" + previewHeight;
WidgetCacheKey key = getObjectKey(o, size);
@@ -576,21 +578,26 @@
private final Object mInfo;
private final int mPreviewHeight;
private final int mPreviewWidth;
- private final PagedViewWidget mCaller;
+ private final WidgetCell mCaller;
PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth,
- int previewHeight, PagedViewWidget caller) {
+ int previewHeight, WidgetCell caller) {
mKey = key;
mInfo = info;
mPreviewHeight = previewHeight;
mPreviewWidth = previewWidth;
mCaller = caller;
+ if (DEBUG) {
+ Log.d(TAG, String.format("%s, %s, %d, %d",
+ mKey, mInfo, mPreviewHeight, mPreviewWidth));
+ }
}
-
@Override
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) {
@@ -608,7 +615,6 @@
mUnusedBitmaps.remove(unusedBitmap);
}
}
-
if (isCancelled()) {
return null;
}
diff --git a/src/com/android/launcher3/WidgetsContainerView.java b/src/com/android/launcher3/WidgetsContainerView.java
deleted file mode 100644
index 7004d8b..0000000
--- a/src/com/android/launcher3/WidgetsContainerView.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.android.launcher3;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-
-class SectionedWidgetsRow {
- String section;
- List<List<Object>> widgets;
-
- public SectionedWidgetsRow(String sc) {
- section = sc;
- }
-}
-
-class SectionedWidgetsAlgorithm {
- public List<SectionedWidgetsRow> computeSectionedWidgetRows(List<Object> sortedWidgets,
- int widgetsPerRow) {
- List<SectionedWidgetsRow> rows = new ArrayList<>();
- LinkedHashMap<String, List<Object>> sections = computeSectionedApps(sortedWidgets);
- for (Map.Entry<String, List<Object>> sectionEntry : sections.entrySet()) {
- String section = sectionEntry.getKey();
- SectionedWidgetsRow row = new SectionedWidgetsRow(section);
- List<Object> widgets = sectionEntry.getValue();
- int numRows = (int) Math.ceil((float) widgets.size() / widgetsPerRow);
- for (int i = 0; i < numRows; i++) {
- List<Object> widgetsInRow = new ArrayList<>();
- int offset = i * widgetsPerRow;
- for (int j = 0; j < widgetsPerRow; j++) {
- widgetsInRow.add(widgets.get(offset + j));
- }
- row.widgets.add(widgetsInRow);
- }
- }
- return rows;
- }
-
- private LinkedHashMap<String, List<Object>> computeSectionedApps(List<Object> sortedWidgets) {
- LinkedHashMap<String, List<Object>> sections = new LinkedHashMap<>();
- for (Object info : sortedWidgets) {
- String section = getSection(info);
- List<Object> sectionedWidgets = sections.get(section);
- if (sectionedWidgets == null) {
- sectionedWidgets = new ArrayList<>();
- sections.put(section, sectionedWidgets);
- }
- sectionedWidgets.add(info);
- }
- return sections;
- }
-
- private String getSection(Object widgetOrShortcut) {
- return "UNKNOWN";
- }
-}
-
-/**
- * The widgets list view container.
- */
-public class WidgetsContainerView extends FrameLayout {
-
-
- public WidgetsContainerView(Context context) {
- this(context, null);
- }
-
- public WidgetsContainerView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- protected void onFinishInflate() {
- }
-}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a79add0..9173971 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -71,6 +71,8 @@
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperUtils;
+import com.android.launcher3.widget.PendingAddShortcutInfo;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
import java.util.ArrayList;
import java.util.HashMap;
@@ -1698,7 +1700,11 @@
mLastCustomContentScrollProgress = progress;
- mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);
+ // We should only update the drag layer background alpha if we are not in all apps or the
+ // widgets tray
+ if (mState == State.NORMAL) {
+ mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);
+ }
if (mLauncher.getHotseat() != null) {
mLauncher.getHotseat().setTranslationX(translationX);
@@ -2250,7 +2256,8 @@
float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;
float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;
float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;
- float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f;
+ // We keep the search bar visible on the workspace and in AllApps now
+ float finalSearchBarAlpha = (stateIsNormal || stateIsNormalHidden) ? 1f : 0f;
float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?
getOverviewModeTranslationY() : 0;
diff --git a/src/com/android/launcher3/widget/PackageItemInfo.java b/src/com/android/launcher3/widget/PackageItemInfo.java
new file mode 100644
index 0000000..d7edf22
--- /dev/null
+++ b/src/com/android/launcher3/widget/PackageItemInfo.java
@@ -0,0 +1,57 @@
+/*
+ * 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.widget;
+
+import android.content.ComponentName;
+import android.graphics.Bitmap;
+
+import com.android.launcher3.ItemInfo;
+
+import java.util.Arrays;
+
+/**
+ * Represents a {@link Package} in the widget tray section.
+ */
+public class PackageItemInfo extends ItemInfo {
+ private static final String TAG = "PackageInfo";
+
+ /**
+ * A bitmap version of the application icon.
+ */
+ public Bitmap iconBitmap;
+
+ /**
+ * Indicates whether we're using a low res icon
+ */
+ public boolean usingLowResIcon;
+
+ public ComponentName componentName;
+
+ int flags = 0;
+
+ PackageItemInfo() {
+ }
+
+ @Override
+ public String toString() {
+ return "PackageItemInfo(title=" + title.toString() + " id=" + this.id
+ + " type=" + this.itemType + " container=" + this.container
+ + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
+ + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos)
+ + " user=" + user + ")";
+ }
+}
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
new file mode 100644
index 0000000..a569850
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -0,0 +1,44 @@
+/*
+ * 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.widget;
+
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.PendingAddItemInfo;
+
+/**
+ * Meta data used for late binding of the short cuts.
+ *
+ * @see {@link PendingAddItemInfo}
+ */
+public class PendingAddShortcutInfo extends PendingAddItemInfo {
+
+ ActivityInfo activityInfo;
+
+ public PendingAddShortcutInfo(ActivityInfo activityInfo) {
+ this.activityInfo = activityInfo;
+ componentName = new ComponentName(activityInfo.packageName, activityInfo.name);
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PendingAddShortcutInfo package=%s, name=%s",
+ activityInfo.packageName, activityInfo.name);
+ }
+}
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
new file mode 100644
index 0000000..db16998
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -0,0 +1,91 @@
+/*
+ * 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.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.os.Bundle;
+import android.os.Parcelable;
+
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.PendingAddItemInfo;
+
+/**
+ * Meta data used for late binding of {@link LauncherAppWidgetProviderInfo}.
+ *
+ * @see {@link PendingAddItemInfo}
+ */
+public class PendingAddWidgetInfo extends PendingAddItemInfo {
+ public int minWidth;
+ public int minHeight;
+ public int minResizeWidth;
+ public int minResizeHeight;
+ public int previewImage;
+ public int icon;
+ public LauncherAppWidgetProviderInfo info;
+ public AppWidgetHostView boundWidget;
+ public Bundle bindOptions = null;
+
+ public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, Parcelable data) {
+ if (i.isCustomWidget) {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+ } else {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+ }
+ this.info = i;
+ componentName = i.provider;
+ minWidth = i.minWidth;
+ minHeight = i.minHeight;
+ minResizeWidth = i.minResizeWidth;
+ minResizeHeight = i.minResizeHeight;
+ previewImage = i.previewImage;
+ icon = i.icon;
+
+ spanX = i.spanX;
+ spanY = i.spanY;
+ minSpanX = i.minSpanX;
+ minSpanY = i.minSpanY;
+ }
+
+ public boolean isCustomWidget() {
+ return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+ }
+
+ // Copy constructor
+ public PendingAddWidgetInfo(PendingAddWidgetInfo copy) {
+ minWidth = copy.minWidth;
+ minHeight = copy.minHeight;
+ minResizeWidth = copy.minResizeWidth;
+ minResizeHeight = copy.minResizeHeight;
+ previewImage = copy.previewImage;
+ icon = copy.icon;
+ info = copy.info;
+ boundWidget = copy.boundWidget;
+ componentName = copy.componentName;
+ itemType = copy.itemType;
+ spanX = copy.spanX;
+ spanY = copy.spanY;
+ minSpanX = copy.minSpanX;
+ minSpanY = copy.minSpanY;
+ bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PendingAddWidgetInfo package=%s, name=%s",
+ componentName.getPackageName(), componentName.getShortClassName());
+ }
+}
diff --git a/src/com/android/launcher3/PagedViewWidget.java b/src/com/android/launcher3/widget/WidgetCell.java
similarity index 79%
rename from src/com/android/launcher3/PagedViewWidget.java
rename to src/com/android/launcher3/widget/WidgetCell.java
index d9ca7be..93ee94a 100644
--- a/src/com/android/launcher3/PagedViewWidget.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.launcher3;
+package com.android.launcher3.widget;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -23,6 +23,7 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
@@ -31,15 +32,31 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest;
import com.android.launcher3.compat.AppWidgetManagerCompat;
/**
- * The linear layout used strictly for the widget/wallpaper tab of the customization tray
+ * The linear layout used strictly for the widget tray.
*/
-public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListener {
+public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
- private static PagedViewWidget sShortpressTarget = null;
+ private static final String TAG = "PagedViewWidget";
+ private static final boolean DEBUG = false;
+
+ // Temporary preset width and height of the image to keep them aligned.
+ //private static final int PRESET_PREVIEW_HEIGHT = 480;
+ //private static final int PRESET_PREVIEW_WIDTH = 480;
+
+ private int mPresetPreviewSize;
+
+ private static WidgetCell sShortpressTarget = null;
private final Rect mOriginalImagePadding = new Rect();
@@ -53,23 +70,25 @@
private WidgetPreviewLoader mWidgetPreviewLoader;
private PreviewLoadRequest mActiveRequest;
- public PagedViewWidget(Context context) {
+ public WidgetCell(Context context) {
this(context, null);
}
- public PagedViewWidget(Context context, AttributeSet attrs) {
+ public WidgetCell(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public PagedViewWidget(Context context, AttributeSet attrs, int defStyle) {
+ public WidgetCell(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final Resources r = context.getResources();
mDimensionsFormatString = r.getString(R.string.widget_dims_format);
+ mPresetPreviewSize = r.getDimensionPixelSize(R.dimen.widget_preview_size);
setWillNotDraw(false);
setClipToPadding(false);
setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
+
}
@Override
@@ -97,6 +116,9 @@
@Override
protected void onDetachedFromWindow() {
+ if (DEBUG) {
+ Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
+ }
super.onDetachedFromWindow();
deletePreview(true);
}
@@ -154,15 +176,19 @@
public int[] getPreviewSize() {
final ImageView i = (ImageView) findViewById(R.id.widget_preview);
int[] maxSize = new int[2];
- maxSize[0] = i.getWidth() - mOriginalImagePadding.left - mOriginalImagePadding.right;
- maxSize[1] = i.getHeight() - mOriginalImagePadding.top;
+ maxSize[0] = mPresetPreviewSize;
+ maxSize[1] = mPresetPreviewSize;
return maxSize;
}
public void applyPreview(Bitmap bitmap) {
FastBitmapDrawable preview = new FastBitmapDrawable(bitmap);
- final PagedViewWidgetImageView image =
- (PagedViewWidgetImageView) findViewById(R.id.widget_preview);
+ final WidgetImageView image =
+ (WidgetImageView) findViewById(R.id.widget_preview);
+ if (DEBUG) {
+ Log.d(TAG, String.format("[tag=%s] applyPreview preview: %s",
+ getTagToString(), preview));
+ }
if (preview != null) {
image.mAllowRequestLayout = false;
image.setImageDrawable(preview);
@@ -177,6 +203,7 @@
}
image.setAlpha(1f);
image.mAllowRequestLayout = true;
+ image.requestLayout();
}
}
@@ -193,8 +220,8 @@
public void run() {
if (sShortpressTarget != null) return;
if (mShortPressListener != null) {
- mShortPressListener.onShortPress(PagedViewWidget.this);
- sShortpressTarget = PagedViewWidget.this;
+ mShortPressListener.onShortPress(WidgetCell.this);
+ sShortpressTarget = WidgetCell.this;
}
mShortPressTriggered = true;
}
@@ -221,7 +248,7 @@
removeShortPressCallback();
if (mShortPressTriggered) {
if (mShortPressListener != null) {
- mShortPressListener.cleanUpShortPress(PagedViewWidget.this);
+ mShortPressListener.cleanUpShortPress(WidgetCell.this);
}
mShortPressTriggered = false;
}
@@ -264,6 +291,10 @@
return;
}
int[] size = getPreviewSize();
+ if (DEBUG) {
+ Log.d(TAG, String.format("[tag=%s] ensurePreview (%d, %d):",
+ getTagToString(), size[0], size[1]));
+ }
if (size[0] <= 0 || size[1] <= 0) {
addOnLayoutChangeListener(this);
@@ -292,4 +323,16 @@
return Math.min(size[0], info.spanX * cellWidth);
}
+
+ /**
+ * Helper method to get the string info of the tag.
+ */
+ private String getTagToString() {
+ if (getTag() instanceof PendingAddWidgetInfo) {
+ return ((PendingAddWidgetInfo)getTag()).toString();
+ } else if (getTag() instanceof PendingAddShortcutInfo) {
+ return ((PendingAddShortcutInfo)getTag()).toString();
+ }
+ return "";
+ }
}
diff --git a/src/com/android/launcher3/PagedViewWidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
similarity index 88%
rename from src/com/android/launcher3/PagedViewWidgetImageView.java
rename to src/com/android/launcher3/widget/WidgetImageView.java
index 7d82795..75167bc 100644
--- a/src/com/android/launcher3/PagedViewWidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.launcher3;
+package com.android.launcher3.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.ImageView;
-public class PagedViewWidgetImageView extends ImageView {
+public class WidgetImageView extends ImageView {
public boolean mAllowRequestLayout = true;
- public PagedViewWidgetImageView(Context context, AttributeSet attrs) {
+ public WidgetImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -44,6 +44,5 @@
super.onDraw(canvas);
canvas.restore();
-
}
}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
new file mode 100644
index 0000000..5aa80a9
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -0,0 +1,372 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.DragController;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.Folder;
+import com.android.launcher3.IconCache;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.WidgetPreviewLoader;
+import com.android.launcher3.Workspace;
+
+import java.util.ArrayList;
+
+/**
+ * The widgets list view container.
+ */
+public class WidgetsContainerView extends FrameLayout implements Insettable, View.OnTouchListener,
+ View.OnLongClickListener, DragSource{
+
+ private static final String TAG = "WidgetContainerView";
+ 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;
+
+ /* Global instances that are used inside this container. */
+ private Launcher mLauncher;
+ private DragController mDragController;
+ private IconCache mIconCache;
+
+ /* Data model for the widget */
+ private WidgetsModel mWidgets;
+
+ /* Recycler view related member variables */
+ private RecyclerView mView;
+ private WidgetsListAdapter mAdapter;
+
+ /* Dragging related. */
+ private boolean mDraggingWidget = false; // TODO(hyunyoungs): seems not needed? check!
+ private Point mLastTouchDownPos = new Point();
+
+ /* Rendering related. */
+ private WidgetPreviewLoader mWidgetPreviewLoader;
+ private Rect mPadding = new Rect();
+
+ public WidgetsContainerView(Context context) {
+ this(context, null);
+ }
+
+ public WidgetsContainerView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = (Launcher) context;
+ mDragController = mLauncher.getDragController();
+
+ mAdapter = new WidgetsListAdapter(context, this, mLauncher, this, mLauncher);
+ mWidgets = new WidgetsModel(context, mAdapter);
+ mAdapter.setWidgetsModel(mWidgets);
+ mIconCache = (LauncherAppState.getInstance()).getIconCache();
+
+ if (DEBUG) {
+ Log.d(TAG, "WidgetsContainerView constructor");
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ if (DEBUG) {
+ Log.d(TAG, String.format("onFinishInflate [widgets size=%d]",
+ mWidgets.getPackageSize()));
+ }
+ mView = (RecyclerView) findViewById(R.id.widgets_list_view);
+ mView.setAdapter(mAdapter);
+ mView.setLayoutManager(new LinearLayoutManager(getContext()));
+ mView.setItemViewCacheSize(WIDGET_CACHE_SIZE);
+
+ mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
+ getPaddingBottom());
+ }
+
+ //
+ // Returns views used for launcher transitions.
+ //
+
+ public View getContentView() {
+ return findViewById(R.id.widgets_list_view);
+ }
+
+ public View getRevealView() {
+ // TODO(hyunyoungs): temporarily use apps view transition.
+ return findViewById(R.id.widgets_reveal_view);
+ }
+
+ public void scrollToTop() {
+ mView.scrollToPosition(0);
+ if (DEBUG) {
+ Log.d(TAG, String.format("scrollToTop, [widgets size=%d]",
+ mWidgets.getPackageSize()));
+ }
+ }
+
+ //
+ // Touch related handling.
+ //
+
+ @Override
+ public boolean onLongClick(View v) {
+ if (DEBUG) {
+ Log.d(TAG, String.format("onLonglick [v=%s]", v));
+ }
+
+ // Return early if this is not initiated from a touch
+ if (!v.isInTouchMode()) return false;
+ // When we have exited all apps or are in transition, disregard long clicks
+ if (!mLauncher.isWidgetsViewVisible() ||
+ mLauncher.getWorkspace().isSwitchingState()) return false;
+ // Return if global dragging is not enabled
+ Log.d(TAG, String.format("onLonglick dragging enabled?.", v));
+ if (!mLauncher.isDraggingEnabled()) return false;
+
+ return beginDragging(v);
+ }
+
+ private boolean beginDragging(View v) {
+ if (v instanceof WidgetCell) {
+ if (!beginDraggingWidget((WidgetCell) v)) {
+ return false;
+ }
+ } else {
+ Log.e(TAG, "Unexpected dragging view: " + v);
+ }
+
+ // We delay entering spring-loaded mode slightly to make sure the UI
+ // thready is free of any work.
+ postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ // We don't enter spring-loaded mode if the drag has been cancelled
+ if (mLauncher.getDragController().isDragging()) {
+ // Go into spring loaded mode (must happen before we startDrag())
+ mLauncher.enterSpringLoadedDragMode();
+ }
+ }
+ }, 150);
+
+ return true;
+ }
+
+ private boolean beginDraggingWidget(WidgetCell v) {
+ mDraggingWidget = true;
+ // Get the widget preview as the drag representation
+ ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
+ PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
+
+ // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
+ // we abort the drag.
+ if (image.getDrawable() == null) {
+ mDraggingWidget = false;
+ return false;
+ }
+
+ // Compose the drag image
+ Bitmap preview;
+ Bitmap outline;
+ float scale = 1f;
+ Point previewPadding = null;
+
+ if (createItemInfo instanceof PendingAddWidgetInfo) {
+ // This can happen in some weird cases involving multi-touch. We can't start dragging
+ // the widget if this is null, so we break out.
+
+ PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
+ int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true);
+
+ FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
+ float minScale = 1.25f;
+ int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
+
+ int[] previewSizeBeforeScale = new int[1];
+ preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
+ maxWidth, null, previewSizeBeforeScale);
+ // Compare the size of the drag preview to the preview in the AppsCustomize tray
+ int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
+ v.getActualItemWidth());
+ scale = previewWidthInAppsCustomize / (float) preview.getWidth();
+
+ // The bitmap in the AppsCustomize tray is always the the same size, so there
+ // might be extra pixels around the preview itself - this accounts for that
+ if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) {
+ int padding =
+ (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2;
+ previewPadding = new Point(padding, 0);
+ }
+ } else {
+ PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
+ Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo);
+ preview = Utilities.createIconBitmap(icon, mLauncher);
+ createItemInfo.spanX = createItemInfo.spanY = 1;
+ }
+
+ // Don't clip alpha values for the drag outline if we're using the default widget preview
+ boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
+ (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
+
+ // Save the preview for the outline generation, then dim the preview
+ outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
+ false);
+
+ // Start the drag
+ mLauncher.lockScreenOrientation();
+ mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
+ mDragController.startDrag(image, preview, this, createItemInfo,
+ DragController.DRAG_ACTION_COPY, previewPadding, scale);
+ outline.recycle();
+ preview.recycle();
+ return true;
+ }
+
+ /*
+ * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
+ */
+ @Override
+ public boolean onTouch(View v, MotionEvent ev) {
+ Log.d(TAG, String.format("onTouch [MotionEvent=%s]", ev));
+ if (ev.getAction() == MotionEvent.ACTION_DOWN ||
+ ev.getAction() == MotionEvent.ACTION_MOVE) {
+ mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
+ }
+ return false;
+ }
+
+ //
+ // Drag related handling methods that implement {@link DragSource} interface.
+ //
+
+ @Override
+ public boolean supportsFlingToDelete() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsAppInfoDropTarget() {
+ return true;
+ }
+
+ /*
+ * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the
+ * {@link DeleteDropTarget} to be invisible.)
+ */
+ @Override
+ public boolean supportsDeleteDropTarget() {
+ return false;
+ }
+
+ @Override
+ public float getIntrinsicIconScaleFactor() {
+ return 0;
+ }
+
+ @Override
+ public void onFlingToDeleteCompleted() {
+ // We just dismiss the drag when we fling, so cleanup here
+ mLauncher.exitSpringLoadedDragModeDelayed(true,
+ Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+ mLauncher.unlockScreenOrientation(false);
+ }
+
+ @Override
+ public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
+ boolean success) {
+ if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
+ !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
+ // Exit spring loaded mode if we have not successfully dropped or have not handled the
+ // drop in Workspace
+ mLauncher.exitSpringLoadedDragModeDelayed(true,
+ Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+ }
+ mLauncher.unlockScreenOrientation(false);
+
+ // Display an error message if the drag failed due to there not being enough space on the
+ // target layout we were dropping on.
+ if (!success) {
+ boolean showOutOfSpaceMessage = false;
+ if (target instanceof Workspace) {
+ int currentScreen = mLauncher.getCurrentWorkspaceScreen();
+ Workspace workspace = (Workspace) target;
+ CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
+ ItemInfo itemInfo = (ItemInfo) d.dragInfo;
+ if (layout != null) {
+ layout.calculateSpans(itemInfo);
+ showOutOfSpaceMessage =
+ !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
+ }
+ }
+ if (showOutOfSpaceMessage) {
+ mLauncher.showOutOfSpaceMessage(false);
+ }
+ d.deferDragViewCleanupPostAnimation = false;
+ }
+ }
+
+ //
+ // Container rendering related.
+ //
+
+ /*
+ * @see Insettable#setInsets(Rect)
+ */
+ @Override
+ public void setInsets(Rect insets) {
+ setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
+ mPadding.right + insets.right, mPadding.bottom + insets.bottom);
+ }
+
+ /**
+ * Initialize the widget data model.
+ */
+ public void addWidgets(ArrayList<Object> widgetsShortcuts, PackageManager pm) {
+ mWidgets.addWidgetsAndShortcuts(widgetsShortcuts, pm);
+ }
+
+ private WidgetPreviewLoader getWidgetPreviewLoader() {
+ if (mWidgetPreviewLoader == null) {
+ mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
+ }
+ return mWidgetPreviewLoader;
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
new file mode 100644
index 0000000..8d1f20c
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -0,0 +1,189 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.WidgetPreviewLoader;
+import com.android.launcher3.compat.UserHandleCompat;
+
+import java.util.List;
+
+/**
+ * List view adapter for the widget tray.
+ *
+ * <p>Memory vs. Performance:
+ * The less number of types of views are inserted into a {@link RecyclerView}, the more recycling
+ * happens and less memory is consumed. {@link #getItemViewType} was not overridden as there is
+ * only a single type of view.
+ */
+public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
+
+ private static final String TAG = "WidgetsListAdapter";
+ private static final boolean DEBUG = false;
+
+ private Context mContext;
+ private Launcher mLauncher;
+ private LayoutInflater mLayoutInflater;
+ private IconCache mIconCache;
+
+ private WidgetsModel mWidgetsModel;
+ private WidgetPreviewLoader mWidgetPreviewLoader;
+
+ private View.OnTouchListener mTouchListener;
+ private View.OnClickListener mIconClickListener;
+ private View.OnLongClickListener mIconLongClickListener;
+
+
+ public WidgetsListAdapter(Context context,
+ View.OnTouchListener touchListener,
+ View.OnClickListener iconClickListener,
+ View.OnLongClickListener iconLongClickListener,
+ Launcher launcher) {
+ mLayoutInflater = LayoutInflater.from(context);
+ mContext = context;
+
+ mTouchListener = touchListener;
+ mIconClickListener = iconClickListener;
+ mIconLongClickListener = iconLongClickListener;
+
+ mLauncher = launcher;
+ mIconCache = LauncherAppState.getInstance().getIconCache();
+ }
+
+ public void setWidgetsModel(WidgetsModel w) {
+ mWidgetsModel = w;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mWidgetsModel.getPackageSize();
+ }
+
+ @Override
+ public void onBindViewHolder(WidgetsRowViewHolder holder, int pos) {
+ String packageName = mWidgetsModel.getPackageName(pos);
+ List<Object> infoList = mWidgetsModel.getSortedWidgets(packageName);
+
+ ViewGroup row = ((ViewGroup) holder.getContent().findViewById(R.id.widgets_cell_list));
+ if (DEBUG) {
+ Log.d(TAG, String.format(
+ "onBindViewHolder [pos=%d, packageName=%s, widget#=%d, row.getChildCount=%d]",
+ pos, packageName, infoList.size(), row.getChildCount()));
+ }
+
+ // Add more views.
+ // if there are too many, hide them.
+ int diff = infoList.size() - row.getChildCount();
+ if (diff > 0) {
+ for (int i = 0; i < diff; i++) {
+ WidgetCell widget = new WidgetCell(mContext);
+ widget = (WidgetCell) mLayoutInflater.inflate(
+ R.layout.widget_cell, row, false);
+
+ // set up touch.
+ widget.setOnClickListener(mIconClickListener);
+ widget.setOnLongClickListener(mIconLongClickListener);
+ widget.setOnTouchListener(mTouchListener);
+ row.addView(widget);
+ }
+ } else if (diff < 0) {
+ for (int i=infoList.size() ; i < row.getChildCount(); i++) {
+ row.getChildAt(i).setVisibility(View.GONE);
+ }
+ }
+
+ // Bind the views in the application info section.
+ PackageItemInfo infoOut = mWidgetsModel.getPackageItemInfo(packageName);
+ if (infoOut.usingLowResIcon) {
+ mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(),
+ false /* useLowResIcon */, infoOut);
+ mWidgetsModel.setPackageItemInfo(packageName, infoOut);
+ }
+ ((TextView) holder.getContent().findViewById(R.id.section)).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);
+ if (getWidgetPreviewLoader() == null || widget == null) {
+ return;
+ }
+ if (infoList.get(i) instanceof LauncherAppWidgetProviderInfo) {
+ LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) infoList.get(i);
+ PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(info, null);
+ widget.setTag(pawi);
+ widget.applyFromAppWidgetProviderInfo(info, -1, mWidgetPreviewLoader);
+ } else if (infoList.get(i) instanceof ResolveInfo) {
+ ResolveInfo info = (ResolveInfo) infoList.get(i);
+ PendingAddShortcutInfo pasi = new PendingAddShortcutInfo(info.activityInfo);
+ widget.setTag(pasi);
+ widget.applyFromResolveInfo(mLauncher.getPackageManager(), info, mWidgetPreviewLoader);
+ }
+ widget.setVisibility(View.VISIBLE);
+ widget.ensurePreview();
+ }
+ // TODO(hyunyoungs): Draw the scrollable indicator.
+ }
+
+ @Override
+ public WidgetsRowViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("\nonCreateViewHolder, [widget#=%d]", viewType));
+ }
+
+ ViewGroup container = (ViewGroup) mLayoutInflater.inflate(
+ R.layout.widgets_list_row_view, parent, false);
+ return new WidgetsRowViewHolder(container);
+ }
+
+ @Override
+ public long getItemId(int pos) {
+ return pos;
+ }
+
+ private WidgetPreviewLoader getWidgetPreviewLoader() {
+ if (mWidgetPreviewLoader == null) {
+ mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
+ }
+ return mWidgetPreviewLoader;
+ }
+
+ /**
+ * TODO(hyunyoungs): this is temporary. Figure out the width of each widget cell
+ * and then check if the total sum is longer than the parent width.
+ */
+ private void addScrollableIndicator(int contentSize, ViewGroup parent) {
+ if (contentSize > 2) {
+ ViewGroup indicator = (ViewGroup) parent.findViewById(R.id.scrollable_indicator);
+ indicator.setVisibility(View.VISIBLE);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsModel.java b/src/com/android/launcher3/widget/WidgetsModel.java
new file mode 100644
index 0000000..463c79e
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsModel.java
@@ -0,0 +1,140 @@
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherModel.WidgetAndShortcutNameComparator;
+import com.android.launcher3.compat.UserHandleCompat;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Widgets data model that is used by the adapters of the widget views and controllers.
+ *
+ * <p> The widgets and shortcuts are organized using package name as its index.
+ */
+public class WidgetsModel {
+
+ private static final String TAG = "WidgetsModel";
+ private static final boolean DEBUG = false;
+
+ /* List of packages that is tracked by this model. */
+ private List<String> mPackageNames = new ArrayList<>();
+
+ private Map<String, PackageItemInfo> mPackageItemInfoList = new HashMap<>();
+
+ /* Map of widgets and shortcuts that are tracked per package. */
+ private Map<String, ArrayList<Object>> mWidgetsList = new HashMap<>();
+
+ /* Notifies the adapter when data changes. */
+ private RecyclerView.Adapter mAdapter;
+
+ private Comparator mWidgetAndShortcutNameComparator;
+
+ private IconCache mIconCache;
+
+ public WidgetsModel(Context context, RecyclerView.Adapter adapter) {
+ mAdapter = adapter;
+ mWidgetAndShortcutNameComparator = new WidgetAndShortcutNameComparator(context);
+ mIconCache = LauncherAppState.getInstance().getIconCache();
+ }
+
+ // Access methods that may be deleted if the private fields are made package-private.
+ public int getPackageSize() {
+ return mPackageNames.size();
+ }
+
+ // Access methods that may be deleted if the private fields are made package-private.
+ public String getPackageName(int pos) {
+ return mPackageNames.get(pos);
+ }
+
+ public PackageItemInfo getPackageItemInfo(String packageName) {
+ return mPackageItemInfoList.get(packageName);
+ }
+
+ public List<Object> getSortedWidgets(String packageName) {
+ return mWidgetsList.get(packageName);
+ }
+
+ public void addWidgetsAndShortcuts(ArrayList<Object> widgetsShortcuts, PackageManager pm) {
+ if (DEBUG) {
+ Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + widgetsShortcuts.size());
+ }
+
+ // clear the lists.
+ mPackageNames.clear();
+ mWidgetsList.clear();
+
+ // add and update.
+ for (Object o: widgetsShortcuts) {
+ String packageName = "";
+ if (o instanceof LauncherAppWidgetProviderInfo) {
+ LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o;
+ packageName = widgetInfo.provider.getPackageName();
+ } else if (o instanceof ResolveInfo) {
+ ResolveInfo resolveInfo = (ResolveInfo) o;
+ packageName = resolveInfo.activityInfo.packageName;
+ } else {
+ Log.e(TAG, String.format("addWidgetsAndShortcuts, nothing added for class=%s",
+ o.getClass().toString()));
+
+ }
+
+ ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(packageName);
+ if (widgetsShortcutsList != null) {
+ widgetsShortcutsList.add(o);
+ } else {
+ widgetsShortcutsList = new ArrayList<Object>();
+ widgetsShortcutsList.add(o);
+ mWidgetsList.put(packageName, widgetsShortcutsList);
+ mPackageNames.add(packageName);
+ }
+ }
+ for (String packageName: mPackageNames) {
+ PackageItemInfo pInfo = mPackageItemInfoList.get(packageName);
+ if (pInfo == null) {
+ pInfo = new PackageItemInfo();
+ mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(),
+ true /* useLowResIcon */, pInfo);
+ mPackageItemInfoList.put(packageName, pInfo);
+ }
+ }
+
+ // sort.
+ sortPackageList();
+ for (String packageName: mPackageNames) {
+ Collections.sort(mWidgetsList.get(packageName), mWidgetAndShortcutNameComparator);
+ }
+
+ // notify.
+ mAdapter.notifyDataSetChanged();
+ }
+
+ private void sortPackageList() {
+ Collections.sort(mPackageNames, new Comparator<String>() {
+ @Override
+ public int compare(String lhs, String rhs) {
+ String lhsTitle = mPackageItemInfoList.get(lhs).title.toString();
+ String rhsTitle = mPackageItemInfoList.get(rhs).title.toString();
+ return lhsTitle.compareTo(rhsTitle);
+ }
+ });
+ }
+
+ public void setPackageItemInfo(String packageName, PackageItemInfo infoOut) {
+ mPackageItemInfoList.put(packageName, infoOut);
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsRowView.java b/src/com/android/launcher3/widget/WidgetsRowView.java
new file mode 100644
index 0000000..5466738
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsRowView.java
@@ -0,0 +1,90 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+import com.android.launcher3.R;
+
+/**
+ * Layout used for widget tray rows for each app. For performance, this view can be replaced with
+ * a {@link RecyclerView} in the future if we settle on scrollable single row for the widgets.
+ * If we decide on collapsable grid, then HorizontalScrollView can be replaced with a
+ * {@link GridLayout}.
+ */
+public class WidgetsRowView extends HorizontalScrollView {
+ static final String TAG = "WidgetsRow";
+
+ private Runnable mOnLayoutListener;
+ private String mAppName;
+
+ public WidgetsRowView(Context context, String appName) {
+ super(context, null, 0);
+ mAppName = appName;
+ }
+
+ /**
+ * Clears all the key listeners for the individual widgets.
+ */
+ public void resetChildrenOnKeyListeners() {
+ int childCount = getChildCount();
+ for (int j = 0; j < childCount; ++j) {
+ getChildAt(j).setOnKeyListener(null);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ TextView tv = (TextView) findViewById(R.id.widget_name);
+ tv.setText(mAppName);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mOnLayoutListener = null;
+ }
+
+ public void setOnLayoutListener(Runnable r) {
+ mOnLayoutListener = r;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (mOnLayoutListener != null) {
+ mOnLayoutListener.run();
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean result = super.onTouchEvent(event);
+ return result;
+ }
+
+ public static class LayoutParams extends FrameLayout.LayoutParams {
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
new file mode 100644
index 0000000..99a192c
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
@@ -0,0 +1,36 @@
+/*
+ * 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.widget;
+
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class WidgetsRowViewHolder extends ViewHolder {
+
+ ViewGroup mContent;
+
+ public WidgetsRowViewHolder(ViewGroup v) {
+ super(v);
+ mContent = v;
+ }
+
+ ViewGroup getContent() {
+ return mContent;
+ }
+}