am 328acffd: (-s ours) am 2e8ba1c1: am 8ff6cb60: DO NOT MERGE
* commit '328acffd8b2ba73693da76ce85581661db45c5aa':
DO NOT MERGE
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 444dbd8..f78a1b2 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -45,7 +45,9 @@
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Launcher2_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Launcher2_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Launcher2_intermediates)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
\ No newline at end of file
+# ************************************************
diff --git a/proguard.flags b/proguard.flags
index 19c8fd5..c2b2c65 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -20,6 +20,17 @@
public void setHoverAlpha(float);
}
+-keep class com.android.launcher2.DragLayer$LayoutParams {
+ public void setWidth(int);
+ public int getWidth();
+ public void setHeight(int);
+ public int getHeight();
+ public void setX(int);
+ public int getX();
+ public void setY(int);
+ public int getY();
+}
+
-keep class com.android.launcher2.CellLayout$LayoutParams {
public void setWidth(int);
public int getWidth();
diff --git a/res/anim/all_apps_2d_fade_in.xml b/res/anim/all_apps_2d_fade_in.xml
index 0f1e4f4..9d2171a 100644
--- a/res/anim/all_apps_2d_fade_in.xml
+++ b/res/anim/all_apps_2d_fade_in.xml
@@ -20,4 +20,4 @@
android:fromAlpha="0.0"
android:toAlpha="1.0"
- android:duration="@integer/config_allAppsFadeInTime" />
+ android:duration="@integer/config_appsCustomizeFadeInTime" />
diff --git a/res/anim/all_apps_2d_fade_out.xml b/res/anim/all_apps_2d_fade_out.xml
index cc47691..90520c7 100644
--- a/res/anim/all_apps_2d_fade_out.xml
+++ b/res/anim/all_apps_2d_fade_out.xml
@@ -20,4 +20,4 @@
android:fromAlpha="1.0"
android:toAlpha="0.0"
- android:duration="@integer/config_allAppsFadeOutTime" />
+ android:duration="@integer/config_appsCustomizeFadeOutTime" />
diff --git a/res/anim/fade_in_slow.xml b/res/anim/fade_in_slow.xml
index 0f1e4f4..9d2171a 100644
--- a/res/anim/fade_in_slow.xml
+++ b/res/anim/fade_in_slow.xml
@@ -20,4 +20,4 @@
android:fromAlpha="0.0"
android:toAlpha="1.0"
- android:duration="@integer/config_allAppsFadeInTime" />
+ android:duration="@integer/config_appsCustomizeFadeInTime" />
diff --git a/res/anim/fade_out_slow.xml b/res/anim/fade_out_slow.xml
index cc47691..90520c7 100644
--- a/res/anim/fade_out_slow.xml
+++ b/res/anim/fade_out_slow.xml
@@ -20,4 +20,4 @@
android:fromAlpha="1.0"
android:toAlpha="0.0"
- android:duration="@integer/config_allAppsFadeOutTime" />
+ android:duration="@integer/config_appsCustomizeFadeOutTime" />
diff --git a/res/drawable-hdpi/box_launcher_top_normal.9.png b/res/drawable-hdpi/box_launcher_top_normal.9.png
index 98997ad..af04b07 100644
--- a/res/drawable-hdpi/box_launcher_top_normal.9.png
+++ b/res/drawable-hdpi/box_launcher_top_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi/box_launcher_top_pressed.9.png b/res/drawable-hdpi/box_launcher_top_pressed.9.png
index f52fd48..af04b07 100644
--- a/res/drawable-hdpi/box_launcher_top_pressed.9.png
+++ b/res/drawable-hdpi/box_launcher_top_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/box_launcher_top_selected.9.png b/res/drawable-hdpi/box_launcher_top_selected.9.png
index 8cacf0e..af04b07 100644
--- a/res/drawable-hdpi/box_launcher_top_selected.9.png
+++ b/res/drawable-hdpi/box_launcher_top_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi/focused_bg.9.png b/res/drawable-hdpi/focused_bg.9.png
new file mode 100644
index 0000000..1b0d3fa
--- /dev/null
+++ b/res/drawable-hdpi/focused_bg.9.png
Binary files differ
diff --git a/res/drawable-hdpi/folder_bg.9.png b/res/drawable-hdpi/folder_bg.9.png
new file mode 100644
index 0000000..6f1bbe5
--- /dev/null
+++ b/res/drawable-hdpi/folder_bg.9.png
Binary files differ
diff --git a/res/drawable-large-hdpi/home_press.9.png b/res/drawable-hdpi/home_press.9.png
similarity index 100%
rename from res/drawable-large-hdpi/home_press.9.png
rename to res/drawable-hdpi/home_press.9.png
Binary files differ
diff --git a/res/drawable-large-hdpi/ic_home_delete_holo_dark.png b/res/drawable-hdpi/ic_home_delete_holo_dark.png
similarity index 100%
rename from res/drawable-large-hdpi/ic_home_delete_holo_dark.png
rename to res/drawable-hdpi/ic_home_delete_holo_dark.png
Binary files differ
diff --git a/res/drawable-large-hdpi/ic_home_delete_hover_holo_dark.png b/res/drawable-hdpi/ic_home_delete_hover_holo_dark.png
similarity index 100%
rename from res/drawable-large-hdpi/ic_home_delete_hover_holo_dark.png
rename to res/drawable-hdpi/ic_home_delete_hover_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_home_info_holo_dark.png b/res/drawable-hdpi/ic_home_info_holo_dark.png
new file mode 100644
index 0000000..02df4e1
--- /dev/null
+++ b/res/drawable-hdpi/ic_home_info_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/wallpaper_divider.png b/res/drawable-hdpi/wallpaper_divider.png
new file mode 100644
index 0000000..2f92d60
--- /dev/null
+++ b/res/drawable-hdpi/wallpaper_divider.png
Binary files differ
diff --git a/res/drawable-mdpi/box_launcher_top_normal.9.png b/res/drawable-mdpi/box_launcher_top_normal.9.png
index 8adf2cf..af04b07 100644
--- a/res/drawable-mdpi/box_launcher_top_normal.9.png
+++ b/res/drawable-mdpi/box_launcher_top_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi/box_launcher_top_pressed.9.png b/res/drawable-mdpi/box_launcher_top_pressed.9.png
index 7a20c54..af04b07 100644
--- a/res/drawable-mdpi/box_launcher_top_pressed.9.png
+++ b/res/drawable-mdpi/box_launcher_top_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/box_launcher_top_selected.9.png b/res/drawable-mdpi/box_launcher_top_selected.9.png
index 9e636f0..af04b07 100644
--- a/res/drawable-mdpi/box_launcher_top_selected.9.png
+++ b/res/drawable-mdpi/box_launcher_top_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi/focused_bg.9.png b/res/drawable-mdpi/focused_bg.9.png
new file mode 100644
index 0000000..1b0d3fa
--- /dev/null
+++ b/res/drawable-mdpi/focused_bg.9.png
Binary files differ
diff --git a/res/drawable-mdpi/folder_bg.9.png b/res/drawable-mdpi/folder_bg.9.png
new file mode 100644
index 0000000..6f1bbe5
--- /dev/null
+++ b/res/drawable-mdpi/folder_bg.9.png
Binary files differ
diff --git a/res/drawable-large-mdpi/home_press.9.png b/res/drawable-mdpi/home_press.9.png
similarity index 100%
rename from res/drawable-large-mdpi/home_press.9.png
rename to res/drawable-mdpi/home_press.9.png
Binary files differ
diff --git a/res/drawable-large-mdpi/ic_home_delete_holo_dark.png b/res/drawable-mdpi/ic_home_delete_holo_dark.png
similarity index 100%
rename from res/drawable-large-mdpi/ic_home_delete_holo_dark.png
rename to res/drawable-mdpi/ic_home_delete_holo_dark.png
Binary files differ
diff --git a/res/drawable-large-mdpi/ic_home_delete_hover_holo_dark.png b/res/drawable-mdpi/ic_home_delete_hover_holo_dark.png
similarity index 100%
rename from res/drawable-large-mdpi/ic_home_delete_hover_holo_dark.png
rename to res/drawable-mdpi/ic_home_delete_hover_holo_dark.png
Binary files differ
diff --git a/res/drawable-large-mdpi/ic_home_info_holo_dark.png b/res/drawable-mdpi/ic_home_info_holo_dark.png
similarity index 100%
rename from res/drawable-large-mdpi/ic_home_info_holo_dark.png
rename to res/drawable-mdpi/ic_home_info_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/wallpaper_divider.png b/res/drawable-mdpi/wallpaper_divider.png
new file mode 100644
index 0000000..1b453c5
--- /dev/null
+++ b/res/drawable-mdpi/wallpaper_divider.png
Binary files differ
diff --git a/res/drawable-nodpi/apps_customize_bg_gradient.9.png b/res/drawable-nodpi/apps_customize_bg_gradient.9.png
new file mode 100644
index 0000000..e766bd6
--- /dev/null
+++ b/res/drawable-nodpi/apps_customize_bg_gradient.9.png
Binary files differ
diff --git a/res/drawable-large/button_bg.xml b/res/drawable/button_bg.xml
similarity index 85%
rename from res/drawable-large/button_bg.xml
rename to res/drawable/button_bg.xml
index 9e6e1ff..a830594 100644
--- a/res/drawable-large/button_bg.xml
+++ b/res/drawable/button_bg.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -15,6 +15,7 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:drawable="@drawable/focused_bg" />
<item android:state_pressed="true" android:drawable="@drawable/home_press" />
<item android:drawable="@android:color/transparent" />
</selector>
diff --git a/res/drawable/delete_zone_selector.xml b/res/drawable/delete_zone_selector.xml
index 0c54b1d7..e2b37f4 100644
--- a/res/drawable/delete_zone_selector.xml
+++ b/res/drawable/delete_zone_selector.xml
@@ -19,6 +19,6 @@
-->
<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/trashcan" />
- <item android:drawable="@drawable/trashcan_hover" />
+ <item android:drawable="@drawable/ic_home_delete_holo_dark" />
+ <item android:drawable="@drawable/ic_home_delete_hover_holo_dark" />
</transition>
diff --git a/res/drawable-large/button_bg.xml b/res/drawable/focusable_view_bg.xml
similarity index 77%
copy from res/drawable-large/button_bg.xml
copy to res/drawable/focusable_view_bg.xml
index 9e6e1ff..66661e2 100644
--- a/res/drawable-large/button_bg.xml
+++ b/res/drawable/focusable_view_bg.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -15,6 +15,5 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true" android:drawable="@drawable/home_press" />
- <item android:drawable="@android:color/transparent" />
+ <item android:state_focused="true" android:drawable="@drawable/focused_bg" />
</selector>
diff --git a/res/layout-land/all_apps_2d.xml b/res/layout-land/all_apps_2d.xml
deleted file mode 100644
index b7fcd45..0000000
--- a/res/layout-land/all_apps_2d.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!-- Sapphire gets 2D all apps view -->
-<com.android.launcher2.AllApps2D
- xmlns:android="http://schemas.android.com/apk/res/android"
-
- android:id="@+id/all_apps_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="2dip"
- android:background="#FF000000">
-
- <GridView android:id="@+id/all_apps_2d_grid"
- android:tag="all_apps_2d_grid"
- android:scrollbars="none"
- android:drawSelectorOnTop="false"
- android:listSelector="@drawable/grid_selector"
- android:verticalSpacing="10dip"
- android:numColumns="6"
- android:fadingEdgeLength="48dip"
- android:cacheColorHint="#FF000000"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:layout_marginRight="@dimen/button_bar_height_portrait"
- android:nextFocusRight="@+id/all_apps_2d_home"
- android:nextFocusUp="@null"
- android:nextFocusLeft="@null"
- android:nextFocusDown="@null"
- />
-
- <view
- class="com.android.launcher2.AllApps2D$HomeButton"
- android:id="@+id/all_apps_2d_home"
- android:tag="all_apps_2d_home"
- android:src="@drawable/home_button"
- android:background="#FF000000"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:layout_height="wrap_content"
- android:layout_width="@dimen/button_bar_height_portrait"
- android:paddingBottom="@dimen/status_bar_height"
- android:nextFocusLeft="@+id/all_apps_2d_grid"
- android:nextFocusDown="@null"
- android:nextFocusUp="@null"
- android:nextFocusRight="@null"
- />
-
-</com.android.launcher2.AllApps2D>
diff --git a/res/layout-land/application.xml b/res/layout-land/application.xml
index 6e8c31e..9ed1fa1 100644
--- a/res/layout-land/application.xml
+++ b/res/layout-land/application.xml
@@ -15,4 +15,6 @@
-->
<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/WorkspaceIcon.Landscape" />
+ style="@style/WorkspaceIcon.Landscape"
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 6e797f8..b2b2c9f 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -22,8 +22,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <include layout="@layout/all_apps" />
-
<!-- The workspace contains 5 screens of cells -->
<com.android.launcher2.Workspace
android:id="@+id/workspace"
@@ -43,6 +41,12 @@
</com.android.launcher2.Workspace>
+ <include layout="@layout/apps_customize_pane"
+ android:id="@+id/apps_customize_pane"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible" />
+
<com.android.launcher2.ClippedImageView
android:id="@+id/previous_screen"
android:layout_width="93dip"
@@ -96,38 +100,26 @@
android:layout_height="fill_parent"
android:layout_width="@dimen/button_bar_height_portrait"
android:layout_gravity="right|center_vertical"
- android:layout_marginBottom="@dimen/half_status_bar_height"
- >
-
+ android:layout_marginBottom="@dimen/half_status_bar_height">
+ <ImageView
+ android:id="@+id/hotseat_left"
+ style="@style/HotseatButton.Left"
+ android:layout_below="@id/all_apps_button"
+ android:src="@drawable/hotseat_phone"
+ android:onClick="launchHotSeat" />
<com.android.launcher2.HandleView
style="@style/HotseatButton"
android:id="@+id/all_apps_button"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
-
android:src="@drawable/all_apps_button"
- launcher:direction="vertical"
- />
-
- <ImageView
- android:id="@+id/hotseat_left"
- style="@style/HotseatButton.Left"
- android:layout_below="@id/all_apps_button"
-
- android:src="@drawable/hotseat_phone"
-
- android:onClick="launchHotSeat"
- />
-
+ launcher:direction="vertical" />
<ImageView
android:id="@+id/hotseat_right"
style="@style/HotseatButton.Right"
android:layout_above="@id/all_apps_button"
-
android:src="@drawable/hotseat_browser"
-
- android:onClick="launchHotSeat"
- />
+ android:onClick="launchHotSeat" />
</RelativeLayout>
</com.android.launcher2.DragLayer>
diff --git a/res/layout-land/user_folder.xml b/res/layout-land/user_folder.xml
index 5da4aa5..b814462 100644
--- a/res/layout-land/user_folder.xml
+++ b/res/layout-land/user_folder.xml
@@ -14,8 +14,11 @@
limitations under the License.
-->
-<com.android.launcher2.UserFolder xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical">
+<com.android.launcher2.Folder
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+ android:orientation="vertical"
+ android:background="@drawable/folder_bg">
<Button
android:id="@+id/folder_close"
@@ -29,17 +32,23 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:background="@drawable/box_launcher_bottom">
+ android:layout_height="0dip"
+ android:layout_weight="1">
- <GridView
+ <com.android.launcher2.CellLayout
android:id="@id/folder_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#ff333333"
+ launcher:cellWidth="@dimen/folder_cell_width"
+ launcher:cellHeight="@dimen/folder_cell_height"
+ launcher:xAxisStartPadding="0dip"
+ launcher:xAxisEndPadding="0dip"
+ launcher:yAxisStartPadding="0dip"
+ launcher:yAxisEndPadding="0dip"
+
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollbarStyle="insideInset"
android:drawSelectorOnTop="false"
@@ -49,4 +58,4 @@
android:numColumns="5" />
</FrameLayout>
-</com.android.launcher2.UserFolder>
+</com.android.launcher2.Folder>
diff --git a/res/layout-large-land/application.xml b/res/layout-large-land/application.xml
index 2598e5a..9393f7e 100644
--- a/res/layout-large-land/application.xml
+++ b/res/layout-large-land/application.xml
@@ -15,4 +15,6 @@
-->
<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/WorkspaceIcon.Landscape" />
+ style="@style/WorkspaceIcon.Landscape"
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout-large/all_apps_no_items_placeholder.xml b/res/layout-large/all_apps_no_items_placeholder.xml
index 247870c..b766df1 100644
--- a/res/layout-large/all_apps_no_items_placeholder.xml
+++ b/res/layout-large/all_apps_no_items_placeholder.xml
@@ -32,4 +32,5 @@
android:drawablePadding="0dip"
android:maxLines="2"
- android:fadingEdge="horizontal" />
+ android:fadingEdge="horizontal"
+ android:focusable="false" />
diff --git a/res/layout-large/all_apps_paged_view_application.xml b/res/layout-large/all_apps_paged_view_application.xml
index e5f07bf..16e5d82 100644
--- a/res/layout-large/all_apps_paged_view_application.xml
+++ b/res/layout-large/all_apps_paged_view_application.xml
@@ -21,9 +21,12 @@
launcher:blurColor="#FF6B8CF0"
launcher:outlineColor="#FF8CD2FF"
+ style="@style/WorkspaceIcon.AllApps"
+
android:id="@+id/application_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
- style="@style/WorkspaceIcon.AllApps" />
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout-large/all_apps_tabbed.xml b/res/layout-large/all_apps_tabbed.xml
index 9937338..b00b3c3 100644
--- a/res/layout-large/all_apps_tabbed.xml
+++ b/res/layout-large/all_apps_tabbed.xml
@@ -32,7 +32,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@drawable/tab_unselected_holo">
- <TabWidget
+ <com.android.launcher2.FocusOnlyTabWidget
android:id="@android:id/tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -50,7 +50,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:visibility="invisible"/>
+ android:visibility="invisible"
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true" />
<TextView
android:id="@+id/market_button"
android:layout_width="wrap_content"
@@ -64,7 +66,9 @@
android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
android:shadowDx="0.0"
android:shadowDy="0.0"
- android:shadowRadius="2.0" />
+ android:shadowRadius="2.0"
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true" />
</FrameLayout>
<com.android.launcher2.DeleteZone
android:id="@+id/all_apps_delete_zone"
@@ -84,7 +88,10 @@
android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
android:shadowDx="0.0"
android:shadowDy="0.0"
- android:shadowRadius="2.0" />
+ android:shadowRadius="2.0"
+
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true" />
</RelativeLayout>
<FrameLayout
android:id="@android:id/tabcontent"
diff --git a/res/layout-large/button_bar.xml b/res/layout-large/button_bar.xml
index 5c96c5c..62115f7 100644
--- a/res/layout-large/button_bar.xml
+++ b/res/layout-large/button_bar.xml
@@ -15,31 +15,34 @@
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+ android:focusable="false">
<!-- Global search icon -->
<ImageView
- android:id="@+id/search_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
- android:paddingRight="@dimen/toolbar_button_horizontal_padding"
- android:paddingTop="@dimen/toolbar_button_vertical_padding"
- android:paddingBottom="@dimen/toolbar_button_vertical_padding"
- android:src="@drawable/ic_generic_search"
- android:background="@drawable/button_bg"
- android:onClick="onClickSearchButton"
- android:focusable="true"
- android:clickable="true" />
+ android:id="@+id/search_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+ android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+ android:paddingTop="@dimen/toolbar_button_vertical_padding"
+ android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+ android:src="@drawable/ic_generic_search"
+ android:background="@drawable/button_bg"
+ android:onClick="onClickSearchButton"
+
+ android:focusable="true"
+ android:clickable="true"
+ android:contentDescription="@string/accessibility_search_button" />
<ImageView
android:id="@+id/search_divider"
android:src="@drawable/divider_launcher_holo"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_toRightOf="@id/search_button"
+ android:layout_toRightOf="@+id/search_button"
android:paddingTop="@dimen/toolbar_button_vertical_padding"
android:paddingBottom="@dimen/toolbar_button_vertical_padding"
@@ -52,7 +55,7 @@
android:id="@+id/voice_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toRightOf="@id/search_divider"
+ android:layout_toRightOf="@+id/search_divider"
android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
android:paddingRight="@dimen/toolbar_button_horizontal_padding"
android:paddingTop="@dimen/toolbar_button_vertical_padding"
@@ -60,35 +63,12 @@
android:src="@drawable/ic_voice_search"
android:background="@drawable/button_bg"
android:onClick="onClickVoiceButton"
- android:focusable="true"
- android:clickable="true"/>
-
- <ImageView
- android:id="@+id/configure_button"
- android:src="@drawable/ic_home_add_holo_dark"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
- android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
- android:paddingRight="@dimen/toolbar_button_horizontal_padding"
- android:paddingTop="@dimen/toolbar_button_vertical_padding"
- android:paddingBottom="@dimen/toolbar_button_vertical_padding"
- android:background="@drawable/button_bg"
android:focusable="true"
- android:clickable="true" />
- <ImageView
- android:id="@+id/divider"
- android:src="@drawable/divider_launcher_holo"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/configure_button"
- android:paddingTop="@dimen/toolbar_button_vertical_padding"
- android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+ android:clickable="true"
+ android:contentDescription="@string/accessibility_voice_search_button" />
- android:focusable="false"
- android:clickable="true" />
+ <!-- AllApps icon -->
<com.android.launcher2.StrokedTextView
android:id="@+id/all_apps_button"
android:text="@string/all_apps_button_label"
@@ -96,7 +76,7 @@
android:drawableLeft="@drawable/ic_home_all_apps_holo_dark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toLeftOf="@id/divider"
+ android:layout_toLeftOf="@+id/all_apps_divider"
android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
android:paddingRight="@dimen/toolbar_button_horizontal_padding"
android:paddingTop="@dimen/all_apps_button_vertical_padding"
@@ -117,16 +97,38 @@
android:shadowRadius="2.5"
android:focusable="true"
- android:clickable="true" />
+ android:clickable="true"
+ android:contentDescription="@string/accessibility_all_apps_button" />
+
<ImageView
- android:id="@+id/divider_during_drag"
+ android:id="@+id/all_apps_divider"
android:src="@drawable/divider_launcher_holo"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_toLeftOf="@id/configure_button"
+ android:layout_toLeftOf="@+id/configure_button"
android:paddingTop="@dimen/toolbar_button_vertical_padding"
android:paddingBottom="@dimen/toolbar_button_vertical_padding"
- android:visibility="gone" />
+
+ android:focusable="false"
+ android:clickable="true" />
+
+ <!-- Customize icon -->
+ <ImageView
+ android:id="@+id/configure_button"
+ android:src="@drawable/ic_home_add_holo_dark"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+ android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+ android:paddingTop="@dimen/toolbar_button_vertical_padding"
+ android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+ android:background="@drawable/button_bg"
+ android:focusable="true"
+ android:contentDescription="@string/accessibility_customize_button" />
+
+ <!-- Delete icon -->
<com.android.launcher2.DeleteZone
android:id="@+id/delete_zone"
android:text="@string/delete_zone_label_workspace"
@@ -134,12 +136,12 @@
android:drawableLeft="@drawable/delete_zone_selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignRight="@id/configure_button"
+ android:layout_alignRight="@+id/configure_button"
android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
android:paddingRight="@dimen/toolbar_button_horizontal_padding"
android:paddingTop="@dimen/toolbar_button_vertical_padding"
android:paddingBottom="@dimen/toolbar_button_vertical_padding"
- android:background="@drawable/button_bg"
+ android:background="@drawable/button_bg"
android:gravity="center_horizontal|center_vertical"
android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
@@ -150,5 +152,8 @@
android:shadowRadius="2.0"
android:visibility="gone"
- launcher:direction="horizontal" />
-</RelativeLayout>
\ No newline at end of file
+ launcher:direction="horizontal"
+
+ android:focusable="true"
+ android:contentDescription="@string/accessibility_delete_button" />
+</RelativeLayout>
diff --git a/res/layout-large/customization_drawer.xml b/res/layout-large/customization_drawer.xml
index a8f6ce0..d8db066 100644
--- a/res/layout-large/customization_drawer.xml
+++ b/res/layout-large/customization_drawer.xml
@@ -22,7 +22,7 @@
android:layout_height="match_parent">
<!-- The layout_width of this RelativeLayout gets overwritten in
CustomizeTrayTabHost.onFinishInflate -->
- <TabWidget
+ <com.android.launcher2.FocusOnlyTabWidget
android:id="@android:id/tabs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout-large/customize_paged_view_item.xml b/res/layout-large/customize_paged_view_item.xml
index b2e5f08..80d678e 100644
--- a/res/layout-large/customize_paged_view_item.xml
+++ b/res/layout-large/customize_paged_view_item.xml
@@ -25,4 +25,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
- style="@style/WorkspaceIcon.Landscape" />
+ style="@style/WorkspaceIcon.Landscape"
+
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true" />
diff --git a/res/layout-large/customize_paged_view_wallpaper.xml b/res/layout-large/customize_paged_view_wallpaper.xml
index 8c5abc8..d6284c2 100644
--- a/res/layout-large/customize_paged_view_wallpaper.xml
+++ b/res/layout-large/customize_paged_view_wallpaper.xml
@@ -25,7 +25,10 @@
android:paddingBottom="50dp"
launcher:blurColor="#FF6B8CF0"
- launcher:outlineColor="#FF8CD2FF">
+ launcher:outlineColor="#FF8CD2FF"
+
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true">
<!-- The preview image for the wallpaper. -->
<ImageView
diff --git a/res/layout-large/customize_paged_view_widget.xml b/res/layout-large/customize_paged_view_widget.xml
index c0b4552..35791f5 100644
--- a/res/layout-large/customize_paged_view_widget.xml
+++ b/res/layout-large/customize_paged_view_widget.xml
@@ -25,7 +25,10 @@
android:paddingBottom="50dp"
launcher:blurColor="#FF6B8CF0"
- launcher:outlineColor="#FF8CD2FF">
+ launcher:outlineColor="#FF8CD2FF"
+
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true">
<!-- The icon of the widget. -->
<ImageView
diff --git a/res/layout-large/launcher.xml b/res/layout-large/launcher.xml
index acf62f9..6c6fecf 100644
--- a/res/layout-large/launcher.xml
+++ b/res/layout-large/launcher.xml
@@ -20,7 +20,8 @@
android:id="@+id/drag_layer"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:focusable="false">
<!-- The workspace contains 5 screens of cells -->
<com.android.launcher2.Workspace
@@ -41,22 +42,24 @@
<include android:id="@+id/cell5" layout="@layout/workspace_screen" />
</com.android.launcher2.Workspace>
- <include
- layout="@layout/all_apps_tabbed"
- android:id="@+id/all_apps_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top" />
-
<include layout="@layout/button_bar"
android:id="@+id/all_apps_button_cluster"
android:layout_width="fill_parent"
android:layout_height="?android:attr/actionBarSize"
android:layout_gravity="top" />
+ <include
+ layout="@layout/all_apps_tabbed"
+ android:id="@+id/all_apps_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="top"
+ android:visibility="invisible" />
+
<include layout="@layout/customization_drawer"
android:id="@+id/customization_drawer"
android:layout_width="match_parent"
android:layout_height="@dimen/customization_drawer_height"
- android:layout_gravity="bottom" />
+ android:layout_gravity="bottom"
+ android:visibility="invisible" />
</com.android.launcher2.DragLayer>
diff --git a/res/layout-large/tab_widget_indicator.xml b/res/layout-large/tab_widget_indicator.xml
index 7794e29..c09c853 100644
--- a/res/layout-large/tab_widget_indicator.xml
+++ b/res/layout-large/tab_widget_indicator.xml
@@ -14,6 +14,6 @@
limitations under the License.
-->
-<TextView
+<com.android.launcher2.AccessibleTabView
xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/TabIndicator" />
+ style="@style/TabIndicator.Wide" />
diff --git a/res/layout-port/all_apps_2d.xml b/res/layout-port/all_apps_2d.xml
deleted file mode 100644
index 081cba2..0000000
--- a/res/layout-port/all_apps_2d.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!-- Sapphire gets 2D all apps view -->
-<com.android.launcher2.AllApps2D
- xmlns:android="http://schemas.android.com/apk/res/android"
-
- android:id="@+id/all_apps_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="2dip"
- android:background="#FF000000">
-
- <GridView android:id="@+id/all_apps_2d_grid"
- android:tag="all_apps_2d_grid"
- android:scrollbars="none"
- android:drawSelectorOnTop="false"
- android:listSelector="@drawable/grid_selector"
- android:verticalSpacing="10dip"
- android:numColumns="4"
- android:fadingEdgeLength="48dip"
- android:cacheColorHint="#FF000000"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="@dimen/button_bar_height"
- android:layout_marginTop="8dip"
- android:nextFocusDown="@+id/all_apps_2d_home"
- android:nextFocusUp="@null"
- android:nextFocusLeft="@null"
- android:nextFocusRight="@null"
- />
-
- <view
- class="com.android.launcher2.AllApps2D$HomeButton"
- android:id="@+id/all_apps_2d_home"
- android:tag="all_apps_2d_home"
- android:src="@drawable/home_button"
- android:background="#FF000000"
- android:layout_centerHorizontal="true"
- android:layout_alignParentBottom="true"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/button_bar_height"
- android:nextFocusUp="@+id/all_apps_2d_grid"
- android:nextFocusDown="@null"
- android:nextFocusLeft="@null"
- android:nextFocusRight="@null"
- />
-
-</com.android.launcher2.AllApps2D>
diff --git a/res/layout-port/application.xml b/res/layout-port/application.xml
index 32c1510..ddc8354 100644
--- a/res/layout-port/application.xml
+++ b/res/layout-port/application.xml
@@ -15,4 +15,6 @@
-->
<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/WorkspaceIcon.Portrait" />
+ style="@style/WorkspaceIcon.Portrait"
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index b7c61d8..c7bcbb0 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -22,8 +22,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <include layout="@layout/all_apps" />
-
<!-- The workspace contains 5 screens of cells -->
<com.android.launcher2.Workspace
android:id="@+id/workspace"
@@ -41,6 +39,12 @@
</com.android.launcher2.Workspace>
+ <include layout="@layout/apps_customize_pane"
+ android:id="@+id/apps_customize_pane"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible" />
+
<ImageView
android:id="@+id/previous_screen"
android:layout_width="93dip"
@@ -89,39 +93,26 @@
android:layout_width="fill_parent"
android:layout_height="@dimen/button_bar_height"
android:layout_gravity="bottom|center_horizontal"
- android:paddingTop="2dip"
- >
-
+ android:paddingTop="2dip">
+ <ImageView
+ android:id="@+id/hotseat_left"
+ style="@style/HotseatButton.Left"
+ android:layout_toLeftOf="@id/all_apps_button"
+ android:src="@drawable/hotseat_phone"
+ android:onClick="launchHotSeat" />
<com.android.launcher2.HandleView
style="@style/HotseatButton"
android:id="@+id/all_apps_button"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
-
android:src="@drawable/all_apps_button"
- launcher:direction="horizontal"
- />
-
- <ImageView
- android:id="@+id/hotseat_left"
- style="@style/HotseatButton.Left"
- android:layout_toLeftOf="@id/all_apps_button"
-
- android:src="@drawable/hotseat_phone"
-
- android:onClick="launchHotSeat"
- />
-
+ launcher:direction="horizontal" />
<ImageView
android:id="@+id/hotseat_right"
style="@style/HotseatButton.Right"
android:layout_toRightOf="@id/all_apps_button"
-
android:src="@drawable/hotseat_browser"
-
- android:onClick="launchHotSeat"
- />
-
+ android:onClick="launchHotSeat" />
</RelativeLayout>
</com.android.launcher2.DragLayer>
diff --git a/res/layout-port/user_folder.xml b/res/layout-port/user_folder.xml
index 0e6df66..4901eb2 100644
--- a/res/layout-port/user_folder.xml
+++ b/res/layout-port/user_folder.xml
@@ -14,12 +14,15 @@
limitations under the License.
-->
-<com.android.launcher2.UserFolder xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical">
-
+<com.android.launcher2.Folder
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+ android:orientation="vertical"
+ android:background="@drawable/folder_bg">
+
<Button
android:id="@+id/folder_close"
- android:background="@drawable/box_launcher_top"
+ android:background="@drawable/box_launcher_top"
android:gravity="left|center_vertical"
android:textSize="14sp"
android:textColor="#404040"
@@ -29,23 +32,30 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:background="@drawable/box_launcher_bottom">
- <GridView
+ android:layout_height="0dip"
+ android:layout_weight="1">
+
+ <com.android.launcher2.CellLayout
android:id="@id/folder_content"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="match_parent"
android:cacheColorHint="#ff333333"
+ launcher:cellWidth="@dimen/folder_cell_width"
+ launcher:cellHeight="@dimen/folder_cell_height"
+ launcher:xAxisStartPadding="0dip"
+ launcher:xAxisEndPadding="0dip"
+ launcher:yAxisStartPadding="0dip"
+ launcher:yAxisEndPadding="0dip"
+
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollbarStyle="insideInset"
android:drawSelectorOnTop="false"
android:listSelector="@drawable/grid_selector"
android:verticalSpacing="10dip"
- android:numColumns="4" />
+ android:numColumns="5" />
</FrameLayout>
-</com.android.launcher2.UserFolder>
+</com.android.launcher2.Folder>
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
deleted file mode 100644
index fadf736..0000000
--- a/res/layout/all_apps.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!-- switch to all_apps_3d on devices that support RenderScript -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <include layout="@layout/all_apps_2d" />
-</merge>
diff --git a/res/layout/application_list.xml b/res/layout/application_list.xml
deleted file mode 100644
index b515c9e..0000000
--- a/res/layout/application_list.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2008, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
-
- android:paddingLeft="10dip"
-
- android:orientation="horizontal">
-
- <ImageView android:id="@+id/icon"
- android:layout_width="@android:dimen/app_icon_size"
- android:layout_height="@android:dimen/app_icon_size"
- android:layout_gravity="center_vertical"
- android:scaleType="fitCenter" />
-
- <LinearLayout
- android:layout_width="0dip"
- android:layout_weight="1.0"
- android:layout_height="match_parent"
-
- android:paddingLeft="8dip"
- android:paddingRight="8dip"
-
- android:orientation="vertical"
- android:gravity="center_vertical">
-
- <TextView android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
-
- android:singleLine="true"
- android:ellipsize="end"
-
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <TextView android:id="@+id/description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
-
- android:layout_below="@id/name"
- android:layout_alignLeft="@id/name"
-
- android:singleLine="true"
- android:ellipsize="end"
-
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary" />
-
- </LinearLayout>
-
-</LinearLayout>
diff --git a/res/layout/all_apps_3d.xml b/res/layout/apps_customize_application.xml
similarity index 60%
rename from res/layout/all_apps_3d.xml
rename to res/layout/apps_customize_application.xml
index 7975df4..4f36326 100644
--- a/res/layout/all_apps_3d.xml
+++ b/res/layout/apps_customize_application.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -14,20 +14,19 @@
limitations under the License.
-->
-<!-- Replace with AllAppsView to use 2D version -->
-<com.android.launcher2.AllApps3D
+<com.android.launcher2.PagedViewIcon
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
- android:id="@+id/all_apps_view"
+ style="@style/WorkspaceIcon.AllApps"
+
+ android:id="@+id/application_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:gravity="center_horizontal"
- android:scrollbarStyle="outsideInset"
- android:drawSelectorOnTop="false"
- android:listSelector="@drawable/grid_selector"
- android:verticalSpacing="10dip"
- android:numColumns="4"
- android:fadingEdgeLength="20dip"
- android:padding="2dip"
- android:cacheColorHint="#FF000000"
- />
+ launcher:blurColor="#FF6B8CF0"
+ launcher:outlineColor="#FF8CD2FF"
+
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
new file mode 100644
index 0000000..05884ef
--- /dev/null
+++ b/res/layout/apps_customize_pane.xml
@@ -0,0 +1,102 @@
+<?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.launcher2.AppsCustomizeTabHost
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/apps_customize_bg_gradient">
+ <!-- The layout_width of the tab bar gets overriden to align the content
+ with the text in the tabs in AppsCustomizeTabHost. -->
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/apps_customize_tab_bar_height"
+ android:layout_gravity="center_horizontal">
+ <com.android.launcher2.FocusOnlyTabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="left"
+ android:background="@drawable/tab_unselected_holo"
+ android:tabStripEnabled="false" />
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="right">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:visibility="gone">
+ <com.android.launcher2.ApplicationInfoDropTarget
+ android:id="@+id/all_apps_info_target"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:drawableLeft="@drawable/ic_home_info_holo_dark"
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true"
+ android:visibility="gone" />
+ <com.android.launcher2.DeleteZone
+ style="@style/DeleteZone"
+ android:id="@+id/all_apps_delete_zone"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true"
+ android:visibility="gone"
+ launcher:direction="horizontal" />
+ </LinearLayout>
+ <TextView
+ style="@style/MarketButton"
+ android:id="@+id/market_button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:background="@drawable/tab_widget_indicator_selector"
+ android:focusable="true" />
+ </FrameLayout>
+ </FrameLayout>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <com.android.launcher2.AppsCustomizePagedView
+ android:id="@+id/apps_customize_pane_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ launcher:cellCountX="@integer/all_apps_view_cellCountX"
+ launcher:cellCountY="@integer/all_apps_view_cellCountY"
+ launcher:pageLayoutWidthGap="@dimen/all_apps_view_pageLayoutWidthGap"
+ launcher:pageLayoutHeightGap="@dimen/all_apps_view_pageLayoutHeightGap"
+ launcher:pageLayoutPaddingTop="@dimen/all_apps_view_pageLayoutPaddingTop"
+ launcher:pageLayoutPaddingBottom="@dimen/all_apps_view_pageLayoutPaddingBottom"
+ launcher:pageLayoutPaddingLeft="@dimen/all_apps_view_pageLayoutPaddingLeft"
+ launcher:pageLayoutPaddingRight="@dimen/all_apps_view_pageLayoutPaddingRight"
+ launcher:widgetCellWidthGap="@dimen/apps_customize_widget_cell_width_gap"
+ launcher:widgetCellHeightGap="@dimen/apps_customize_widget_cell_height_gap"
+ launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x"
+ launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y"
+ launcher:wallpaperCountX="@integer/apps_customize_wallpaper_cell_count_x"
+ launcher:wallpaperCountY="@integer/apps_customize_wallpaper_cell_count_y" />
+ </FrameLayout>
+ </LinearLayout>
+</com.android.launcher2.AppsCustomizeTabHost>
diff --git a/res/layout/apps_customize_wallpaper.xml b/res/layout/apps_customize_wallpaper.xml
new file mode 100644
index 0000000..d93825f
--- /dev/null
+++ b/res/layout/apps_customize_wallpaper.xml
@@ -0,0 +1,68 @@
+<?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.launcher2.PagedViewWidget
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical"
+
+ launcher:blurColor="#FF6B8CF0"
+ launcher:outlineColor="#FF8CD2FF"
+
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true">
+
+ <!-- The wallpaper preview. -->
+ <ImageView
+ android:id="@+id/widget_preview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:paddingBottom="10dp"
+ android:adjustViewBounds="true"
+ android:scaleType="fitStart" />
+
+ <!-- The divider image. -->
+ <ImageView
+ android:id="@+id/divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:paddingTop="10dp"
+ android:paddingBottom="10dp"
+ android:src="@drawable/widget_divider" />
+
+ <!-- The name of the wallpaper. -->
+ <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/widget_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:gravity="left|bottom"
+
+ android:textColor="#FFFFFFFF"
+ android:textSize="14sp"
+ android:shadowColor="#FF000000"
+ android:shadowDx="0.0"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0"
+
+ android:maxLines="2"
+ android:fadingEdge="horizontal" />
+</com.android.launcher2.PagedViewWidget>
diff --git a/res/layout/apps_customize_widget.xml b/res/layout/apps_customize_widget.xml
new file mode 100644
index 0000000..9d0764c
--- /dev/null
+++ b/res/layout/apps_customize_widget.xml
@@ -0,0 +1,74 @@
+<?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.launcher2.PagedViewWidget
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical"
+
+ launcher:blurColor="#FF6B8CF0"
+ launcher:outlineColor="#FF8CD2FF"
+
+ android:background="@drawable/focusable_view_bg"
+ android:focusable="true">
+
+ <!-- The icon of the widget. -->
+ <ImageView
+ android:id="@+id/widget_preview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:paddingBottom="5dp"
+ android:adjustViewBounds="true"
+ android:scaleType="fitStart" />
+
+ <!-- The name of the widget. -->
+ <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/widget_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:gravity="left|bottom"
+
+ android:textColor="#FFFFFFFF"
+ android:textSize="14sp"
+ android:shadowColor="#FF000000"
+ android:shadowDx="0.0"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0"
+
+ android:maxLines="2"
+ android:fadingEdge="horizontal" />
+
+ <!-- The original dimensions of the widget (can't be the same text as above due to different
+ style. -->
+ <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/widget_dims"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:gravity="left|bottom"
+
+ android:textColor="#FF999999"
+ android:textSize="14sp"
+ android:shadowColor="#99000000"
+ android:shadowDx="0.0"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0" />
+</com.android.launcher2.PagedViewWidget>
diff --git a/res/layout-large-port/tab_widget_indicator.xml b/res/layout/tab_widget_indicator.xml
similarity index 83%
rename from res/layout-large-port/tab_widget_indicator.xml
rename to res/layout/tab_widget_indicator.xml
index b113b7b..b3694fe 100644
--- a/res/layout-large-port/tab_widget_indicator.xml
+++ b/res/layout/tab_widget_indicator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -14,6 +14,6 @@
limitations under the License.
-->
-<TextView
+<com.android.launcher2.AccessibleTabView
xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/TabIndicator.Portrait" />
+ style="@style/TabIndicator" />
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index df0a210..cb4c1f3 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"الرئيسية"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"إزالة"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"إزالة"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"بحث"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"البحث الصوتي"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"التطبيقات"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"تخصيص"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"إزالة"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"إزالة التحديث"</string>
<string name="menu_add" msgid="3065046628354640854">"إضافة"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"إدارة التطبيقات"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 5be82f1..0f0f07d 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Начало"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Премахване"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Деинсталиране"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Търсене"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Гласово търсене"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Приложения"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Персонализиране"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Премахване"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Деинстал. на актуализацията"</string>
<string name="menu_add" msgid="3065046628354640854">"Добавяне"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Управление на приложенията"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 56ada67..85058ba 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Pàgina d\'inici"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Elimina"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstal·la"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Cerca"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Cerca per veu"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicacions"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personalitza"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Elimina"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstal·la l\'actualització"</string>
<string name="menu_add" msgid="3065046628354640854">"Afegeix"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gestiona les aplicacions"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 47fb726..af04cb6 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Plocha"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odebrat"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinstalovat"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Hledat"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Hlasové vyhledávání"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikace"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizovat"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Odebrat"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinstalovat aktualizaci"</string>
<string name="menu_add" msgid="3065046628354640854">"Přidat"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Spravovat aplikace"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index f481234..10bd77f 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Start"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Fjern"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Afinstaller"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Søg"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Stemmesøgning"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Programmer"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Tilpas"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Fjern"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Afinstaller opdatering"</string>
<string name="menu_add" msgid="3065046628354640854">"Tilføj"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Administrer programmer"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index fdb2a41..87124a3 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Startseite"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Entfernen"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Deinstallieren"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Suchen"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Sprachsuche"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Apps"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Anpassen"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Entfernen"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Update deinstallieren"</string>
<string name="menu_add" msgid="3065046628354640854">"Hinzufügen"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Apps verwalten"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 5e9b644..59ef926 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Αρχική σελίδα"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Κατάργηση"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Κατάργηση εγκατάστασης"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Αναζήτηση"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Φωνητική αναζήτηση"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Εφαρμογές"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Προσαρμογή"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Κατάργηση"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Κατάργηση εγκατάστασης ενημέρωσης"</string>
<string name="menu_add" msgid="3065046628354640854">"Προσθήκη"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Διαχείριση εφαρμογών"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 7334133..f07752c 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remove"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Uninstall"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Search"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Voice Search"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Applications"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Customise"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Remove"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Uninstall update"</string>
<string name="menu_add" msgid="3065046628354640854">"Add"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Manage apps"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index eadcbae..46781f1 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Página principal"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Quitar"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Buscar"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Búsqueda por voz"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicaciones"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizar"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Eliminar"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar la actualización"</string>
<string name="menu_add" msgid="3065046628354640854">"Agregar"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Administrar aplicaciones"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 90b4e1d..3d162b9 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Inicio"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eliminar del escritorio"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Buscar"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Búsqueda por voz"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicaciones"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizar"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Eliminar"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar actualización"</string>
<string name="menu_add" msgid="3065046628354640854">"Añadir"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Administrar aplicaciones"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 0d53ea5..1170d79 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"صفحه اصلی"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"حذف"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"حذف نصب"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"جستجو"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"جستجوی صوتی"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"برنامه های کاربردی"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"سفارشی کردن"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"حذف"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"حذف نصب به روزرسانی"</string>
<string name="menu_add" msgid="3065046628354640854">"افزودن"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"مدیریت برنامه ها"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 7b02c8d..4e40e56 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Etusivu"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Poista"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Poista"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Haku"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Äänihaku"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Sovellukset"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Muokkaa"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Poista"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Poista päivitys"</string>
<string name="menu_add" msgid="3065046628354640854">"Lisää"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Hallinnoi sovelluksia"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 7ff39d7..83d71d8 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Page d\'accueil"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Supprimer"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Désinstaller"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Rechercher"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Recherche vocale"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Applications"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personnaliser"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Supprimer"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Désinstaller la mise à jour"</string>
<string name="menu_add" msgid="3065046628354640854">"Ajouter"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gérer les applications"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index ea09db0..34487a5 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Početna"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Ukloni"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Deinstaliraj"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Pretraži"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Glasovno pretraživanje"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikacije"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Prilagodi"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Ukloni"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Deinstalacija ažuriranja"</string>
<string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Upravljaj aplikacijama"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 77d9dda..dfa267b 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Főoldal"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eltávolítás"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Eltávolítás"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Keresés"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Hangalapú keresés"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Alkalmazások"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Személyre szabás"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Törlés"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Eltávolítja a frissítést"</string>
<string name="menu_add" msgid="3065046628354640854">"Hozzáadás"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Alkalmazások kezelése"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index a7ed856..d9a6d28 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Rumah"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Hapus"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Copot pemasangan"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Telusuri"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Penelusuran Suara"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikasi"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Ubahsuaikan"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Hapus"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Copot pemasangan pemutakhiran"</string>
<string name="menu_add" msgid="3065046628354640854">"Tambahkan"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Mengelola aplikasi"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 003db6f..0a1f4fd 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Rimuovi"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Disinstalla"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Cerca"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Ricerca vocale"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Applicazioni"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizza"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Rimuovi"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Disinstalla aggiornamento"</string>
<string name="menu_add" msgid="3065046628354640854">"Aggiungi"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gestisci applicazioni"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 75df245..535cf73 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"דף הבית"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"הסר"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"הסר התקנה"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"חפש"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"חיפוש קולי"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"יישומים"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"התאם אישית"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"הסר"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"הסר את התקנת העדכון"</string>
<string name="menu_add" msgid="3065046628354640854">"הוסף"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"נהל יישומים"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index ee6ab83..4b2d31d 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"ホーム"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"削除"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"アンインストール"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"検索"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"音声検索"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"アプリケーション"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"カスタマイズ"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"削除"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"アップデートをアンインストール"</string>
<string name="menu_add" msgid="3065046628354640854">"追加"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"アプリの管理"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index f2b8b0c..9f6ee4a 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"홈"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"삭제"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"제거"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"검색"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"음성 검색"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"애플리케이션"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"맞춤설정"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"삭제"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"업데이트 제거"</string>
<string name="menu_add" msgid="3065046628354640854">"추가"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"애플리케이션 관리"</string>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 159cbb4..e1b0214 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -17,5 +17,23 @@
<resources>
<dimen name="workspace_cell_width">106dip</dimen>
<dimen name="workspace_cell_height">74dip</dimen>
+ <dimen name="folder_cell_width">100dip</dimen>
+ <dimen name="folder_cell_height">74dip</dimen>
<dimen name="button_bar_height">62dip</dimen>
+
+ <integer name="all_apps_view_cellCountX">6</integer>
+ <integer name="all_apps_view_cellCountY">3</integer>
+ <dimen name="all_apps_view_pageLayoutWidthGap">10dp</dimen>
+ <dimen name="all_apps_view_pageLayoutHeightGap">5dp</dimen>
+ <dimen name="all_apps_view_pageLayoutPaddingTop">10dp</dimen>
+ <dimen name="all_apps_view_pageLayoutPaddingBottom">10dp</dimen>
+ <dimen name="all_apps_view_pageLayoutPaddingLeft">2dp</dimen>
+ <dimen name="all_apps_view_pageLayoutPaddingRight">2dp</dimen>
+
+ <dimen name="apps_customize_widget_cell_width_gap">30dp</dimen>
+ <dimen name="apps_customize_widget_cell_height_gap">0dp</dimen>
+ <integer name="apps_customize_widget_cell_count_x">3</integer>
+ <integer name="apps_customize_widget_cell_count_y">1</integer>
+ <integer name="apps_customize_wallpaper_cell_count_x">3</integer>
+ <integer name="apps_customize_wallpaper_cell_count_y">1</integer>
</resources>
diff --git a/res/values-large/config.xml b/res/values-large/config.xml
index 56c7bc6..99ee1ec 100644
--- a/res/values-large/config.xml
+++ b/res/values-large/config.xml
@@ -1,63 +1,26 @@
<resources>
- <!-- NOTE: Many of the all apps values here are also used for the customization drawer -->
-
- <!-- Duration in milliseconds of the fade-in/out of the icons as they are being dragged
- from the AllApps or Customization trays -->
- <integer name="icon_allAppsCustomizeFadeInTime">150</integer>
- <integer name="icon_allAppsCustomizeFadeOutTime">200</integer>
- <integer name="icon_allAppsCustomizeFadeAlpha">102</integer>
-
- <!-- Duration in milliseconds of the all apps / configuration zoom-in animation. -->
- <!-- NB: This should be less than the workspaceShrinkTime as they happen together. -->
- <integer name="config_allAppsZoomInTime">1000</integer>
- <integer name="config_allAppsFadeInTime">250</integer>
-
- <!-- Duration in milliseconds of the transition between tabs in the all apps/customize
- tray -->
- <integer name="config_tabTransitionTime">100</integer>
-
- <!-- Duration in milliseconds of the all apps zoom-out animation -->
- <!-- NB: This should be less than the workspaceUnshrinkTime as they happen together. -->
- <integer name="config_allAppsZoomOutTime">1200</integer>
-
- <!-- Scaling factor used in the all apps zooming animations -->
- <integer name="config_allAppsZoomScaleFactor">20</integer>
-
- <!-- Duration in milliseconds of the all apps / configuration zoom-in animation. -->
- <!-- NB: This should be less than the workspaceShrinkTime as they happen together. -->
+<!-- AllApps/Customize/AppsCustomize -->
+ <!-- Fade/zoom in/out duration & scale in the Customize transition.
+ Note: This should be less than the workspaceShrinkTime as they happen together. -->
<integer name="config_customizeZoomInTime">800</integer>
+ <integer name="config_customizeZoomOutTime">600</integer>
+ <integer name="config_customizeZoomScaleFactor">7</integer>
<integer name="config_customizeFadeInTime">800</integer>
- <!-- Duration in milliseconds of the all apps zoom-out animation -->
- <!-- NB: This should be less than the workspaceUnshrinkTime as they happen together. -->
- <integer name="config_customizeZoomOutTime">600</integer>
-
- <!-- Scaling factor used in the all apps zooming animations -->
- <integer name="config_customizeZoomScaleFactor">7</integer>
+ <!-- The slope, in percent, of the drag movement needed to drag an item out of
+ Customize (y / x * 100%) -->
+ <integer name="config_customizationDrawerDragSlopeThreshold">150</integer>
<!-- Duration in milliseconds of the animations between all apps, customize, & home.
NOTE: If these are changed, the toolbar animation times below should also be. -->
- <integer name="config_allAppsFadeOutTime">500</integer>
<integer name="config_customizeWorkspaceShrinkTime">800</integer>
- <integer name="config_allAppsWorkspaceShrinkTime">1000</integer>
- <integer name="config_workspaceUnshrinkTime">650</integer>
- <!-- Duration in milliseconds toolbar fade in and fade out animations.
- NOTE: Fade in and fade out time should together be less the transition
- animations between all apps, customize, & the workspace. -->
- <integer name="config_toolbarButtonFadeInTime">350</integer>
- <integer name="config_toolbarButtonFadeOutTime">200</integer>
-
+<!-- Workspace -->
<!-- When dragging items on the workspace, how much bigger (in pixels) the dragged view
should be, as compared to the original view. If 0, it will not be scaled at all.
Should be an even number, for pixel alignment. -->
<integer name="config_dragViewExtraPixels">0</integer>
- <!-- When dragging items on the workspace, the number of pixels by which the position of
- the drag view should be offset from the position of the original view. -->
- <integer name="config_dragViewOffsetX">0</integer>
- <integer name="config_dragViewOffsetY">-12</integer>
-
<!-- When items are dropped on the mini screens in customize mode, we have a bounce animation
of the bright green hover outline, and then fade out the outline at the end. These are
the values used in that animation -->
@@ -66,13 +29,4 @@
<integer name="config_screenOnDropScaleDownDuration">200</integer>
<integer name="config_screenOnDropAlphaFadeDelay">350</integer>
<integer name="config_screenOnDropAlphaFadeDuration">50</integer>
-
- <!-- The slope, in percent, of the drag movement needed to drag an item out of the customization
- drawer (y / x * 100%) -->
- <integer name="config_customizationDrawerDragSlopeThreshold">150</integer>
- <integer name="config_allAppsDrawerDragSlopeThreshold">150</integer>
-
- <style name="config_orientation">
- <item name="@android:screenOrientation">unspecified</item>
- </style>
</resources>
diff --git a/res/values-large/dimens.xml b/res/values-large/dimens.xml
index 2b97697..11f85ab 100644
--- a/res/values-large/dimens.xml
+++ b/res/values-large/dimens.xml
@@ -15,6 +15,8 @@
-->
<resources>
+ <dimen name="apps_customize_cell_width">96dp</dimen>
+ <dimen name="apps_customize_cell_height">96dp</dimen>
<dimen name="workspace_cell_width">96dip</dimen>
<dimen name="workspace_cell_height">96dip</dimen>
@@ -40,7 +42,6 @@
<dimen name="allAppsSmallScreenVerticalMarginLandscape">30dip</dimen>
<dimen name="allAppsSmallScreenVerticalMarginPortrait">60dip</dimen>
- <dimen name="delete_zone_drawable_padding">8dip</dimen>
<dimen name="all_apps_button_drawable_padding">0dip</dimen>
<dimen name="all_apps_button_vertical_padding">4dip</dimen>
@@ -62,4 +63,9 @@
<!-- How much the content view of an alert dialog should be inset (currently used
for the WallpaperChooser in XLarge mode) -->
<dimen name="alert_dialog_content_inset">0dp</dimen>
+
+ <!-- When dragging items on the workspace, the number of dps by which the position of
+ the drag view should be offset from the position of the original view. -->
+ <dimen name="dragViewOffsetX">0dp</dimen>
+ <dimen name="dragViewOffsetY">-12dp</dimen>
</resources>
diff --git a/res/values-large/styles.xml b/res/values-large/styles.xml
index 7208d97..bcbe038 100644
--- a/res/values-large/styles.xml
+++ b/res/values-large/styles.xml
@@ -41,4 +41,16 @@
<item name="android:paddingTop">0dip</item>
<item name="android:includeFontPadding">false</item>
</style>
+
+ <style name="TabIndicator.Wide">
+ <item name="android:paddingLeft">40dp</item>
+ <item name="android:paddingRight">40dp</item>
+ <item name="android:paddingTop">15dp</item>
+ <item name="android:paddingBottom">20dp</item>
+ <item name="android:textSize">20sp</item>
+ </style>
+
+ <style name="config_orientation">
+ <item name="@android:screenOrientation">unspecified</item>
+ </style>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index acf0e27..e84360d 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Pagrindinis"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Pašalinti"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Pašalinti"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Ieškoti"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Balso paieška"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Programos"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Tinkinti"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Pašalinti"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Pašalinti naujinį"</string>
<string name="menu_add" msgid="3065046628354640854">"Pridėti"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Valdyti programas"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 9c1b389..963c332 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Sākums"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Noņemt"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Atinstalēt"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Meklēt"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Balss meklēšana"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Lietojumprogrammas"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Pielāgot"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Noņemt"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Atinstalēt atjauninājumu"</string>
<string name="menu_add" msgid="3065046628354640854">"Pievienot"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Lietotņu pārvaldība"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index ccdab7e..382bac4 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Startsiden"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Fjern"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Avinstaller"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Søk"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Talesøk"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Applikasjoner"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Tilpass"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Fjern"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Avinstaller oppdateringen"</string>
<string name="menu_add" msgid="3065046628354640854">"Legg til"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Administrer programmer"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 3d7c7ac..abcf29a 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Startpagina"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Verwijderen"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Verwijderen"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Zoeken"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Spraakgestuurd zoeken"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Apps"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Aanpassen"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Verwijderen"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Update verwijderen"</string>
<string name="menu_add" msgid="3065046628354640854">"Toevoegen"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Apps beheren"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f116165..97b54af 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Ekran główny"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Usuń"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinstaluj"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Szukaj"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Wyszukiwanie głosowe"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikacje"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Dostosuj"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Usuń"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinstaluj aktualizację"</string>
<string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Zarządzaj aplikacjami"</string>
diff --git a/res/values-port/dimens.xml b/res/values-port/dimens.xml
index 65a3fd3..7d50c1a 100644
--- a/res/values-port/dimens.xml
+++ b/res/values-port/dimens.xml
@@ -17,4 +17,22 @@
<resources>
<dimen name="workspace_cell_width">80dip</dimen>
<dimen name="workspace_cell_height">100dip</dimen>
+ <dimen name="folder_cell_width">74dip</dimen>
+ <dimen name="folder_cell_height">86dip</dimen>
+
+ <integer name="all_apps_view_cellCountX">4</integer>
+ <integer name="all_apps_view_cellCountY">5</integer>
+ <dimen name="all_apps_view_pageLayoutWidthGap">3dp</dimen>
+ <dimen name="all_apps_view_pageLayoutHeightGap">12dp</dimen>
+ <dimen name="all_apps_view_pageLayoutPaddingTop">15dp</dimen>
+ <dimen name="all_apps_view_pageLayoutPaddingBottom">15dp</dimen>
+ <dimen name="all_apps_view_pageLayoutPaddingLeft">0dp</dimen>
+ <dimen name="all_apps_view_pageLayoutPaddingRight">0dp</dimen>
+
+ <dimen name="apps_customize_widget_cell_width_gap">20dp</dimen>
+ <dimen name="apps_customize_widget_cell_height_gap">40dp</dimen>
+ <integer name="apps_customize_widget_cell_count_x">2</integer>
+ <integer name="apps_customize_widget_cell_count_y">2</integer>
+ <integer name="apps_customize_wallpaper_cell_count_x">1</integer>
+ <integer name="apps_customize_wallpaper_cell_count_y">1</integer>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index a3a5a8d..71f634d 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Página inicial"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remover"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Pesquisar"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Pesquisa por Voz"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicações"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizar"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Remover"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar atualização"</string>
<string name="menu_add" msgid="3065046628354640854">"Adicionar"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gerir aplicações"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 55deb94..2714fde 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Página inicial"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remover"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Pesquisar"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Pesquisa por voz"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicativos"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizar"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Remover"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar atualização"</string>
<string name="menu_add" msgid="3065046628354640854">"Adicionar"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gerenciar aplicativos"</string>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index 1b5729b..a8453ed 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -85,6 +85,16 @@
<skip />
<!-- no translation found for delete_zone_label_all_apps (6664588234817475108) -->
<skip />
+ <!-- no translation found for accessibility_search_button (816822994629942611) -->
+ <skip />
+ <!-- no translation found for accessibility_voice_search_button (3938249215065842475) -->
+ <skip />
+ <!-- no translation found for accessibility_all_apps_button (1595097919145716305) -->
+ <skip />
+ <!-- no translation found for accessibility_customize_button (585539669413531163) -->
+ <skip />
+ <!-- no translation found for accessibility_delete_button (3628162007991023603) -->
+ <skip />
<!-- no translation found for delete_zone_label_all_apps_system_app (3683920959591819044) -->
<skip />
<string name="menu_add" msgid="3065046628354640854">"Agiuntar"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 3a72c51..6bed5d0 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Domiciliu"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eliminaţi"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Dezinstalaţi"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Căutaţi"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Căutare vocală"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicaţii"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizaţi"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Eliminaţi"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Dezinstalaţi actualizarea"</string>
<string name="menu_add" msgid="3065046628354640854">"Adăugaţi"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gestionaţi aplicaţii"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 912c3f4..0456e4c 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Главная"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Удалить"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Удалить"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Поиск"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Голосовой поиск"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Приложения"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Настроить"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Удалить"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Удалить обновление"</string>
<string name="menu_add" msgid="3065046628354640854">"Добавить"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Приложения"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 3cadf3b..064309d 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Domovská stránka"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odstrániť"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinštalovať"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Hľadať"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Hlasové vyhľadávanie"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikácie"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Prispôsobiť"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Odstrániť"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinštalovať aktualizáciu"</string>
<string name="menu_add" msgid="3065046628354640854">"Pridať"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Spravovať aplikácie"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index daf0899..78b5187 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Začetni zaslon"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odstrani"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odstrani"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Išči"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Glasovno iskanje"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Programi"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Prilagodi"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Odstrani"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odstrani posodobitev"</string>
<string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Upravljaj programe"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 1d92080..cbc4bf2 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Почетна"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Уклони"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Деинсталирај"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Претражи"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Гласовна претрага"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Апликације"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Прилагоди"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Уклони"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Деинсталирај ажурирања"</string>
<string name="menu_add" msgid="3065046628354640854">"Додај"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Управљање апликацијама"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 8094f05..68859e3 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Startsida"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Ta bort"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Avinstallera"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Sök"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Röstsökning"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Appar"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Anpassa"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Ta bort"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Avinstallera uppdatering"</string>
<string name="menu_add" msgid="3065046628354640854">"Lägg till"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Hantera appar"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 26c33c9..1562135 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"บ้าน"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"นำออก"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"ถอนการติดตั้ง"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"ค้นหา"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Voice Search"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"แอปพลิเคชัน"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"กำหนดค่า"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"ลบ"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"ถอนการติดตั้งการอัปเดต"</string>
<string name="menu_add" msgid="3065046628354640854">"เพิ่ม"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"จัดการแอปพลิเคชัน"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index f21dc3c..50ed317 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Alisin"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"I-uninstall"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Maghanap"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Paghahanap gamit ang Boses"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Mga Application"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"I-customize"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Alisin"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"I-uninstall ang update"</string>
<string name="menu_add" msgid="3065046628354640854">"Idagdag"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Pamahalaan ang apps"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index bf80bf5..2057828 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Ana Sayfa"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Kaldır"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Yüklemeyi Kaldır"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Ara"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Sesli Arama"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Uygulamalar"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Özelleştir"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Kaldır"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Güncelleme kaldırılsın mı?"</string>
<string name="menu_add" msgid="3065046628354640854">"Ekle"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Uyglm yönet"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 267ca88..b3f0846 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Головна"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Видалити"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Видалити"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Пошук"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Голосовий пошук"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Програми"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Налаштувати"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Видалити"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Видалити оновлення"</string>
<string name="menu_add" msgid="3065046628354640854">"Додати"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Керув. прогр."</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index d3f549f..9238c4a 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Màn hình trang chủ"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"Xóa"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Gỡ cài đặt"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"Tìm kiếm"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Tìm kiếm bằng giọng nói"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Ứng dụng"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"Tùy chỉnh"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"Xóa"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Gỡ cài đặt cập nhật"</string>
<string name="menu_add" msgid="3065046628354640854">"Thêm"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Quản lý ứng dụng"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index a3dc212..b2f228c 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"主屏幕"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"删除"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"卸载"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"搜索"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"语音搜索"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"应用程序"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"自定义"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"删除"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"卸载更新"</string>
<string name="menu_add" msgid="3065046628354640854">"添加"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"管理应用程序"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 2274274..f172ef6 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -67,6 +67,11 @@
<string name="all_apps_home_button_label" msgid="1022222300329398558">"主螢幕"</string>
<string name="delete_zone_label_workspace" msgid="7153615831493049150">"移除"</string>
<string name="delete_zone_label_all_apps" msgid="6664588234817475108">"解除安裝"</string>
+ <string name="accessibility_search_button" msgid="816822994629942611">"搜尋"</string>
+ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"語音搜尋"</string>
+ <string name="accessibility_all_apps_button" msgid="1595097919145716305">"應用程式"</string>
+ <string name="accessibility_customize_button" msgid="585539669413531163">"自訂"</string>
+ <string name="accessibility_delete_button" msgid="3628162007991023603">"移除"</string>
<string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"解除安裝更新"</string>
<string name="menu_add" msgid="3065046628354640854">"新增"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"管理應用程式"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 4f44253..75b93bf 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -109,6 +109,23 @@
<attr name="pageSpacing" format="dimension" />
</declare-styleable>
+ <!-- AppsCustomizePagedView specific attributes. These attributes are used to
+ customize an AppsCustomizePagedView in xml files. -->
+ <declare-styleable name="AppsCustomizePagedView">
+ <!-- Horizontal spacing between widgets and wallpapers -->
+ <attr name="widgetCellWidthGap" format="dimension" />
+ <!-- Vertical spacing between widgets -->
+ <attr name="widgetCellHeightGap" format="dimension" />
+ <!-- Number of widgets horizontally -->
+ <attr name="widgetCountX" format="integer" />
+ <!-- Number of widgets vertically -->
+ <attr name="widgetCountY" format="integer" />
+ <!-- Number of wallpaper pickers horizontally -->
+ <attr name="wallpaperCountX" format="integer" />
+ <!-- Number of wallpaper pickers vertically -->
+ <attr name="wallpaperCountY" format="integer" />
+ </declare-styleable>
+
<!-- CustomizePagedView specific attributes. These attributes are used to customize
a CustomizePagedView view in XML files. -->
<declare-styleable name="CustomizePagedView">
diff --git a/res/values/config.xml b/res/values/config.xml
index c56a8ce..0aa1ee4 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -1,10 +1,41 @@
<resources>
- <integer name="config_allAppsFadeInTime">700</integer>
- <integer name="config_allAppsFadeOutTime">700</integer>
- <integer name="config_allAppsBatchLoadDelay">0</integer>
- <integer name="config_allAppsBatchSize">0</integer>
+<!-- System -->
<bool name="config_hardwareAccelerated">false</bool>
+<!-- AllApps/Customize/AppsCustomize -->
+ <!-- Fade in/out duration of icons being dragged from the trays -->
+ <integer name="config_dragAppsCustomizeIconFadeInDuration">150</integer>
+ <integer name="config_dragAppsCustomizeIconFadeOutDuration">200</integer>
+ <integer name="config_dragAppsCustomizeIconFadeAlpha">100</integer>
+ <integer name="config_workspaceUnshrinkTime">650</integer>
+
+ <!-- Fade/zoom in/out duration & scale in the AllApps transition.
+ Note: This should be less than the workspaceShrinkTime as they happen together. -->
+ <integer name="config_appsCustomizeZoomInTime">1000</integer>
+ <integer name="config_appsCustomizeZoomOutTime">1200</integer>
+ <integer name="config_appsCustomizeZoomScaleFactor">20</integer>
+ <integer name="config_appsCustomizeFadeInTime">250</integer>
+ <integer name="config_appsCustomizeFadeOutTime">500</integer>
+ <integer name="config_appsCustomizeWorkspaceShrinkTime">1000</integer>
+
+ <!-- Tab transition animation duration -->
+ <integer name="config_tabTransitionDuration">100</integer>
+
+ <!-- The slope, in percent, of the drag movement needed to drag an item out of
+ AppsCustomize (y / x * 100%) -->
+ <integer name="config_appsCustomizeDragSlopeThreshold">150</integer>
+
+ <!-- Fade in/out duration of toolbar/button bar icons.
+ Note: In + Out duration together should be less the duration of the transition
+ between AllApps, Customize & the Workspace. -->
+ <integer name="config_toolbarButtonFadeInTime">350</integer>
+ <integer name="config_toolbarButtonFadeOutTime">200</integer>
+
+ <!-- Batch loading for loading in LauncherModel -->
+ <integer name="config_allAppsBatchLoadDelay">0</integer>
+ <integer name="config_allAppsBatchSize">0</integer>
+
+<!-- Workspace -->
<integer name="config_crosshairsFadeInTime">600</integer>
<!-- When dragging an item on the workspace, how much bigger (in pixels) the dragged view
@@ -12,12 +43,6 @@
Should be an even number, for pixel alignment. -->
<integer name="config_dragViewExtraPixels">40</integer>
- <!-- When dragging items on the workspace, the number of pixels by which the position of
- the drag view should be offset from the position of the original view.
- Setting to 1/2 of config_dragViewExtraPixels keeps it centered on its old position. -->
- <integer name="config_dragViewOffsetX">20</integer>
- <integer name="config_dragViewOffsetY">20</integer>
-
<!-- The duration (in ms) of the fade animation on the object outlines, used when
we are dragging objects around on the home screen. -->
<integer name="config_dragOutlineFadeTime">900</integer>
@@ -30,6 +55,9 @@
<integer name="config_dropAnimMaxDuration">400</integer>
+ <!-- The duration of the UserFolder opening and closing animation -->
+ <integer name="config_folderAnimDuration">150</integer>
+
<!-- The distance at which the animation should take the max duration -->
<integer name="config_dropAnimMaxDist">800</integer>
@@ -38,8 +66,4 @@
than the view itself (workspaceScreenBitmapCacheScale) -->
<integer name="config_workspaceScreenBitmapCacheScale">20</integer>
<integer name="config_maxScaleForUsingWorkspaceScreenBitmapCache">50</integer>
-
- <style name="config_orientation">
- <item name="@android:screenOrientation">nosensor</item>
- </style>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d6cd3ee..62e55d2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -15,8 +15,16 @@
-->
<resources>
+<!-- AllApps/Customize/AppsCustomize -->
+ <!-- Size of icons in Workspace/AppsCustomize -->
+ <dimen name="app_icon_size">50dp</dimen>
+ <dimen name="apps_customize_cell_width">68dp</dimen>
+ <dimen name="apps_customize_cell_height">68dp</dimen>
<dimen name="title_texture_width">120px</dimen>
+ <!-- height of the tab bar in AppsCustomize -->
+ <dimen name="apps_customize_tab_bar_height">56dp</dimen>
+
<!-- height of the bottom row of controls -->
<dimen name="button_bar_height">56dip</dimen>
@@ -24,6 +32,24 @@
button_bar_height changes -->
<dimen name="button_bar_height_portrait">56dip</dimen>
+ <!-- extra horizontal spacing between mini screen thumbnails ie. in all
+ apps and in customization mode -->
+ <dimen name="smallScreenExtraSpacing">0dip</dimen>
+
+ <!-- Vertical spacing between edge of screen and mini cell layouts when they
+ are minimized to the bottom in all apps -->
+ <dimen name="allAppsSmallScreenVerticalMarginLandscape">30dip</dimen>
+ <dimen name="allAppsSmallScreenVerticalMarginPortrait">60dip</dimen>
+
+ <!-- height & width of the drop rectangle for the trash icon -->
+ <dimen name="delete_zone_size">70dip</dimen>
+
+ <!-- delete_zone_size_full - button_bar_height_portrait -->
+ <dimen name="delete_zone_padding">14dip</dimen>
+
+ <!-- padding between the delete zone drawable and text -->
+ <dimen name="delete_zone_drawable_padding">8dip</dimen>
+
<!-- roughly a status bar (for vertically centering the all apps
home icon in landscape) -->
<dimen name="status_bar_height">25dip</dimen>
@@ -32,16 +58,13 @@
button cluster in landscape) -->
<dimen name="half_status_bar_height">12dip</dimen>
- <!-- Size of icons in workspace -->
- <dimen name="app_icon_size">50dp</dimen>
-
- <!-- height & width of the drop rectangle for the trash icon -->
- <dimen name="delete_zone_size">70dip</dimen>
-
- <!-- delete_zone_size_full - button_bar_height_portrait -->
- <dimen name="delete_zone_padding">14dip</dimen>
-
+<!-- Dragging -->
<!-- the area at the edge of the screen that makes the workspace go left
or right while you're dragging. -->
<dimen name="scroll_zone">20dp</dimen>
+
+ <!-- When dragging items on the workspace, the number of dps by which the position of
+ the drag view should be offset from the position of the original view. -->
+ <dimen name="dragViewOffsetX">0dp</dimen>
+ <dimen name="dragViewOffsetY">-8dp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index eedbd6a..9ad3e24 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -151,6 +151,17 @@
device. [CHAR_LIMIT=30]-->
<string name="delete_zone_label_all_apps">Uninstall</string>
+ <!-- Accessibility: Search button -->
+ <string name="accessibility_search_button">Search</string>
+ <!-- Accessibility: Voice Search button -->
+ <string name="accessibility_voice_search_button">Voice Search</string>
+ <!-- Accessibility: AllApps button -->
+ <string name="accessibility_all_apps_button">Applications</string>
+ <!-- Accessibility: Customize button -->
+ <string name="accessibility_customize_button">Customize</string>
+ <!-- Accessibility: Delete button -->
+ <string name="accessibility_delete_button">Remove</string>
+
<!-- Label for trash icon in All Apps, when an updated system app is selected. The update will
be uninstalled. [CHAR_LIMIT=30] -->
<string name="delete_zone_label_all_apps_system_app">Uninstall update</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 0c74a6a..abe6ac4 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -35,17 +35,17 @@
</style>
<style name="WorkspaceIcon">
- <item name="android:textSize">13dip</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:shadowColor">#B0000000</item>
- <item name="android:shadowRadius">2.0</item>
- <item name="android:textColor">#FFF</item>
- <item name="android:gravity">center_horizontal</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:paddingLeft">5dip</item>
<item name="android:paddingRight">5dip</item>
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">13dip</item>
+ <item name="android:textColor">#FFF</item>
+ <item name="android:shadowRadius">2.0</item>
+ <item name="android:shadowColor">#B0000000</item>
</style>
<style name="WorkspaceIcon.AllApps">
@@ -54,7 +54,7 @@
<style name="WorkspaceIcon.Portrait">
<item name="android:drawablePadding">5dip</item>
- <item name="android:paddingTop">4dip</item>
+ <item name="android:paddingTop">0dip</item>
<item name="android:layout_marginLeft">3dip</item>
<item name="android:layout_marginRight">3dip</item>
<item name="android:layout_marginTop">13dip</item>
@@ -72,24 +72,19 @@
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">match_parent</item>
<item name="android:gravity">center</item>
- <item name="android:paddingLeft">40dp</item>
- <item name="android:paddingRight">40dp</item>
- <item name="android:paddingTop">15dp</item>
- <item name="android:paddingBottom">20dp</item>
- <item name="android:textColor">@color/tab_widget_indicator_color</item>
+ <item name="android:paddingLeft">15dp</item>
+ <item name="android:paddingRight">15dp</item>
+ <item name="android:paddingTop">10dp</item>
+ <item name="android:paddingBottom">15dp</item>
<item name="android:background">@drawable/tab_widget_indicator_selector</item>
- <item name="android:textSize">20sp</item>
+ <item name="android:textColor">@color/tab_widget_indicator_color</item>
+ <item name="android:textSize">16sp</item>
<item name="android:shadowColor">#393939</item>
<item name="android:shadowDx">0.0</item>
<item name="android:shadowDy">1.0</item>
<item name="android:shadowRadius">1.0</item>
</style>
- <style name="TabIndicator.Portrait">
- <item name="android:paddingLeft">20dp</item>
- <item name="android:paddingRight">20dp</item>
- </style>
-
<style name="SearchButton" parent="@android:style/Widget.Button.Small">
<item name="android:paddingTop">7dip</item>
<item name="android:paddingBottom">9dip</item>
@@ -97,6 +92,29 @@
<item name="android:paddingRight">10dip</item>
</style>
+ <style name="MarketButton">
+ <item name="android:paddingRight">20dp</item>
+ <item name="android:text">@string/market</item>
+ <item name="android:textColor">@color/workspace_all_apps_and_delete_zone_text_color</item>
+ <item name="android:textSize">18sp</item>
+ <item name="android:shadowColor">@color/workspace_all_apps_and_delete_zone_text_shadow_color</item>
+ <item name="android:shadowDx">0.0</item>
+ <item name="android:shadowDy">0.0</item>
+ <item name="android:shadowRadius">2.0</item>
+ </style>
+
+ <style name="DeleteZone">
+ <item name="android:drawableLeft">@drawable/delete_zone_selector</item>
+ <item name="android:drawablePadding">@dimen/delete_zone_drawable_padding</item>
+ <item name="android:paddingRight">20dp</item>
+ <item name="android:textColor">@color/workspace_all_apps_and_delete_zone_text_color</item>
+ <item name="android:textSize">18sp</item>
+ <item name="android:shadowColor">@color/workspace_all_apps_and_delete_zone_text_shadow_color</item>
+ <item name="android:shadowDx">0.0</item>
+ <item name="android:shadowDy">0.0</item>
+ <item name="android:shadowRadius">2.0</item>
+ </style>
+
<style name="HotseatButton">
<item name="android:paddingLeft">12dip</item>
<item name="android:paddingRight">12dip</item>
@@ -116,4 +134,7 @@
<item name="android:background">@drawable/hotseat_bg_right</item>
</style>
+ <style name="config_orientation">
+ <item name="@android:screenOrientation">nosensor</item>
+ </style>
</resources>
diff --git a/src/com/android/launcher2/AccessibleTabView.java b/src/com/android/launcher2/AccessibleTabView.java
new file mode 100644
index 0000000..101f139
--- /dev/null
+++ b/src/com/android/launcher2/AccessibleTabView.java
@@ -0,0 +1,51 @@
+/*
+ * 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.launcher2;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.widget.TextView;
+
+/**
+ * We use a custom tab view to process our own focus traversals.
+ */
+public class AccessibleTabView extends TextView {
+ public AccessibleTabView(Context context) {
+ super(context);
+ }
+
+ public AccessibleTabView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AccessibleTabView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return FocusHelper.handleTabKeyEvent(this, keyCode, event)
+ || super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return FocusHelper.handleTabKeyEvent(this, keyCode, event)
+ || super.onKeyUp(keyCode, event);
+ }
+}
diff --git a/src/com/android/launcher2/AddAdapter.java b/src/com/android/launcher2/AddAdapter.java
index 24c31ff..6f97d72 100644
--- a/src/com/android/launcher2/AddAdapter.java
+++ b/src/com/android/launcher2/AddAdapter.java
@@ -40,7 +40,6 @@
public static final int ITEM_SHORTCUT = 0;
public static final int ITEM_APPWIDGET = 1;
- public static final int ITEM_LIVE_FOLDER = 2;
public static final int ITEM_WALLPAPER = 3;
/**
@@ -76,9 +75,6 @@
mItems.add(new ListItem(res, R.string.group_widgets,
R.drawable.ic_launcher_appwidget, ITEM_APPWIDGET));
- mItems.add(new ListItem(res, R.string.group_live_folders,
- R.drawable.ic_launcher_folder, ITEM_LIVE_FOLDER));
-
mItems.add(new ListItem(res, R.string.group_wallpapers,
R.drawable.ic_launcher_wallpaper, ITEM_WALLPAPER));
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 1cbb999..44af7b7 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -143,7 +143,7 @@
homeButton.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
- mLauncher.closeAllApps(true);
+ mLauncher.showWorkspace(true);
}
});
}
@@ -158,8 +158,10 @@
this(context, attrs);
}
- public void setLauncher(Launcher launcher) {
+ @Override
+ public void setup(Launcher launcher, DragController dragController) {
mLauncher = launcher;
+ mDragController = dragController;
}
public boolean onKey(View v, int keyCode, KeyEvent event) {
@@ -167,7 +169,7 @@
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
- mLauncher.closeAllApps(true);
+ mLauncher.showWorkspace(true);
break;
default:
return false;
@@ -190,7 +192,7 @@
app = new ApplicationInfo(app);
mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
- mLauncher.closeAllApps(true);
+ mLauncher.showWorkspace(true);
return true;
}
@@ -202,11 +204,6 @@
}
@Override
- public void setDragController(DragController dragger) {
- mDragController = dragger;
- }
-
- @Override
public void onDragViewVisible() {
}
@@ -341,6 +338,10 @@
public void surrender() {
}
+
+ public void reset() {
+ // Do nothing
+ }
}
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index 29f49af..0e512c6 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -155,13 +155,6 @@
setRenderScriptGL(sRS);
}
- final DisplayMetrics metrics = getResources().getDisplayMetrics();
- final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
- mColumnsPerPage = isPortrait ? Defines.COLUMNS_PER_PAGE_PORTRAIT :
- Defines.COLUMNS_PER_PAGE_LANDSCAPE;
- mRowsPerPage = isPortrait ? Defines.ROWS_PER_PAGE_PORTRAIT :
- Defines.ROWS_PER_PAGE_LANDSCAPE;
-
if (sRollo != null) {
sRollo.mAllApps = this;
sRollo.mRes = getResources();
@@ -208,8 +201,10 @@
setSoundEffectsEnabled(old);
}
- public void setLauncher(Launcher launcher) {
+ @Override
+ public void setup(Launcher launcher, DragController dragController) {
mLauncher = launcher;
+ mDragController = dragController;
}
@Override
@@ -231,6 +226,12 @@
super.surfaceChanged(holder, format, w, h);
+ final boolean isPortrait = w < h;
+ mColumnsPerPage = isPortrait ? Defines.COLUMNS_PER_PAGE_PORTRAIT :
+ Defines.COLUMNS_PER_PAGE_LANDSCAPE;
+ mRowsPerPage = isPortrait ? Defines.ROWS_PER_PAGE_PORTRAIT :
+ Defines.ROWS_PER_PAGE_LANDSCAPE;
+
if (mSurrendered) return;
mHaveSurface = true;
@@ -350,7 +351,7 @@
if (mArrowNavigation) {
if (mLastSelection == SELECTION_HOME) {
reallyPlaySoundEffect(SoundEffectConstants.CLICK);
- mLauncher.closeAllApps(true);
+ mLauncher.showWorkspace(true);
} else {
int whichApp = sRollo.mScript.get_gSelectedIconIndex();
if (whichApp >= 0) {
@@ -637,7 +638,7 @@
if ((isPortrait && y > mTouchYBorders[mTouchYBorders.length-1]) ||
(!isPortrait && x > mTouchXBorders[mTouchXBorders.length-1])) {
reallyPlaySoundEffect(SoundEffectConstants.CLICK);
- mLauncher.closeAllApps(true);
+ mLauncher.showWorkspace(true);
}
sRollo.setHomeSelected(SELECTED_NONE);
}
@@ -691,10 +692,12 @@
int screenX = mMotionDownRawX - (bmp.getWidth() / 2);
int screenY = mMotionDownRawY - bmp.getHeight();
+ mLauncher.lockScreenOrientation();
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, bmp);
mDragController.startDrag(
bmp, screenX, screenY, this, app, DragController.DRAG_ACTION_COPY);
- mLauncher.closeAllApps(true);
+ mLauncher.showWorkspace(true);
}
return true;
}
@@ -737,16 +740,13 @@
}
@Override
- public void setDragController(DragController dragger) {
- mDragController = dragger;
- }
-
- @Override
public void onDragViewVisible() {
}
@Override
public void onDropCompleted(View target, Object dragInfo, boolean success) {
+ mLauncher.getWorkspace().onDragStopped(success);
+ mLauncher.unlockScreenOrientation();
}
/**
@@ -1045,13 +1045,16 @@
i.ScaleOffset.x = (2.f / 480.f);
i.ScaleOffset.y = 0;
i.ScaleOffset.z = -((float)w / 2) - 0.25f;
- i.ScaleOffset.w = -380.25f;
- i.BendPos.x = 120.f;
- i.BendPos.y = 680.f;
- if (w > h) {
- i.ScaleOffset.z = 40.f;
- i.ScaleOffset.w = h - 40.f;
- i.BendPos.y = 1.f;
+ if (w < h) {
+ // portrait
+ i.ScaleOffset.w = -380.25f;
+ i.BendPos.x = 120.f; // bottom of screen
+ i.BendPos.y = h - 82.f; // top of screen
+ } else {
+ // landscape
+ i.ScaleOffset.w = -206.25f;
+ i.BendPos.x = 50.f;
+ i.BendPos.y = h - 30.f;
}
mUniformAlloc.set(i, 0, true);
}
@@ -1091,7 +1094,7 @@
" float aDy = cos(bendAngle);\n" +
" float aDz = sin(bendAngle);\n" +
- " float scale = (2.0 / 480.0);\n" +
+ " float scale = (2.0 / " + mWidth + ".0);\n" +
" float x = UNI_Position.x + UNI_ImgSize.x * (1.0 - ani) * (ATTRIB_position.x - 0.5);\n" +
" float ys= UNI_Position.y + UNI_ImgSize.y * (1.0 - ani) * ATTRIB_position.y;\n" +
" float y = 0.0;\n" +
@@ -1466,4 +1469,8 @@
sRS.contextDump();
}
}
+
+ public void reset() {
+ // Do nothing
+ }
}
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 87d255e..d9a503f 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -24,6 +24,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -66,6 +67,7 @@
private boolean mAllowHardwareLayerCreation;
private int mPageContentWidth;
+ private boolean mHasMadeSuccessfulDrop;
public AllAppsPagedView(Context context) {
this(context, null);
@@ -88,7 +90,7 @@
Resources r = context.getResources();
setDragSlopeThreshold(
- r.getInteger(R.integer.config_allAppsDrawerDragSlopeThreshold) / 100.0f);
+ r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold) / 100.0f);
// Create a dummy page and set it up to find out the content width (used by our parent)
PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
@@ -119,14 +121,10 @@
}
@Override
- public void setLauncher(Launcher launcher) {
+ public void setup(Launcher launcher, DragController dragController) {
mLauncher = launcher;
mLauncher.setAllAppsPagedView(this);
- }
-
- @Override
- public void setDragController(DragController dragger) {
- mDragController = dragger;
+ mDragController = dragController;
}
public void setAppFilter(int filterType) {
@@ -138,6 +136,10 @@
}
}
+ void resetSuccessfulDropFlag() {
+ mHasMadeSuccessfulDrop = false;
+ }
+
@Override
public void zoom(float zoom, boolean animate) {
mZoom = zoom;
@@ -285,6 +287,16 @@
c.translate((v.getWidth() - icon.getIntrinsicWidth()) / 2, v.getPaddingTop());
icon.draw(c);
+ Rect dragRect = null;
+ if (v instanceof TextView) {
+ int iconSize = getResources().getDimensionPixelSize(R.dimen.app_icon_size);
+ int top = v.getPaddingTop();
+ int left = (b.getWidth() - iconSize) / 2;
+ int right = left + iconSize;
+ int bottom = top + iconSize;
+ dragRect = new Rect(left, top, right, bottom);
+ }
+
// We toggle the checked state _after_ we create the view for the drag in case toggling the
// checked state changes the view's look
if (v instanceof Checkable) {
@@ -304,7 +316,7 @@
// Start the drag
mLauncher.lockScreenOrientation();
mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
- mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, null);
+ mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, dragRect);
b.recycle();
return true;
}
@@ -322,6 +334,12 @@
tearDownDragMode();
mLauncher.getWorkspace().onDragStopped(success);
mLauncher.unlockScreenOrientation();
+
+ if (!success && !mHasMadeSuccessfulDrop) {
+ mLauncher.getWorkspace().shrink(Workspace.ShrinkState.BOTTOM_HIDDEN);
+ } else {
+ mHasMadeSuccessfulDrop |= success;
+ }
}
int getPageContentWidth() {
@@ -450,6 +468,11 @@
// do nothing?
}
+ public void reset() {
+ setCurrentPage(0);
+ invalidatePageData();
+ }
+
private void setupPage(PagedViewCellLayout layout) {
layout.setCellCount(mCellCountX, mCellCountY);
layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, mPageLayoutPaddingRight,
@@ -485,6 +508,7 @@
@Override
public void syncPageItems(int page) {
// Ensure that we have the right number of items on the pages
+ final int numPages = getPageCount();
final int cellsPerPage = mCellCountX * mCellCountY;
final int startIndex = page * cellsPerPage;
final int endIndex = Math.min(startIndex + cellsPerPage, mFilteredApps.size());
@@ -517,6 +541,7 @@
// Add any necessary items
for (int i = curNumPageItems; i < numPageItems; ++i) {
+ final boolean createHolographicOutlines = (numPages > 1);
TextView text = (TextView) mInflater.inflate(
R.layout.all_apps_paged_view_application, layout, false);
text.setOnClickListener(this);
@@ -524,16 +549,17 @@
text.setOnTouchListener(this);
layout.addViewToCellLayout(text, -1, i,
- new PagedViewCellLayout.LayoutParams(0, 0, 1, 1));
+ new PagedViewCellLayout.LayoutParams(0, 0, 1, 1), createHolographicOutlines);
}
// Actually reapply to the existing text views
- final int numPages = getPageCount();
for (int i = startIndex; i < endIndex; ++i) {
final int index = i - startIndex;
final ApplicationInfo info = mFilteredApps.get(i);
+ final boolean createHolographicOutlines = (numPages > 1);
PagedViewIcon icon = (PagedViewIcon) layout.getChildOnPageAt(index);
- icon.applyFromApplicationInfo(info, mPageViewIconCache, true, (numPages > 1));
+ icon.applyFromApplicationInfo(
+ info, mPageViewIconCache, true, createHolographicOutlines);
PagedViewCellLayout.LayoutParams params =
(PagedViewCellLayout.LayoutParams) icon.getLayoutParams();
@@ -555,10 +581,11 @@
}
// Center-align the message
+ final boolean createHolographicOutlines = (numPages > 1);
layout.enableCenteredContent(true);
layout.removeAllViewsOnPage();
layout.addViewToCellLayout(icon, -1, 0,
- new PagedViewCellLayout.LayoutParams(0, 0, 4, 1));
+ new PagedViewCellLayout.LayoutParams(0, 0, 4, 1), createHolographicOutlines);
}
layout.createHardwareLayers();
}
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
index ee7bfc0..96de5a7 100644
--- a/src/com/android/launcher2/AllAppsTabbed.java
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -29,11 +29,13 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
import java.util.ArrayList;
+import java.util.Random;
/**
* Implements a tabbed version of AllApps2D.
@@ -80,6 +82,7 @@
};
// Create the tabs and wire them up properly
+ AllAppsTabKeyEventListener keyListener = new AllAppsTabKeyEventListener();
TextView tabView;
TabWidget tabWidget = (TabWidget) findViewById(com.android.internal.R.id.tabs);
tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
@@ -90,11 +93,17 @@
tabView.setText(mContext.getString(R.string.all_apps_tab_downloaded));
addTab(newTabSpec(TAG_DOWNLOADED).setIndicator(tabView).setContent(contentFactory));
+ // Setup the key listener to jump between the last tab view and the market icon
+ View lastTab = tabWidget.getChildTabViewAt(tabWidget.getTabCount() - 1);
+ lastTab.setOnKeyListener(keyListener);
+ View shopButton = findViewById(R.id.market_button);
+ shopButton.setOnKeyListener(keyListener);
+
setOnTabChangedListener(new OnTabChangeListener() {
public void onTabChanged(String tabId) {
// animate the changing of the tab content by fading pages in and out
final Resources res = getResources();
- final int duration = res.getInteger(R.integer.config_tabTransitionTime);
+ final int duration = res.getInteger(R.integer.config_tabTransitionDuration);
final float alpha = mAllApps.getAlpha();
ValueAnimator alphaAnim = ObjectAnimator.ofFloat(mAllApps, "alpha", alpha, 0.0f).
setDuration(duration);
@@ -134,14 +143,9 @@
}
@Override
- public void setLauncher(Launcher launcher) {
- mAllApps.setLauncher(launcher);
+ public void setup(Launcher launcher, DragController dragController) {
mLauncher = launcher;
- }
-
- @Override
- public void setDragController(DragController dragger) {
- mAllApps.setDragController(dragger);
+ mAllApps.setup(launcher, dragController);
}
@Override
@@ -248,6 +252,10 @@
mAllApps.surrender();
}
+ public void reset() {
+ mAllApps.reset();
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getY() > mAllApps.getBottom()) {
@@ -255,4 +263,12 @@
}
return true;
}
+
+ @Override
+ public int getDescendantFocusability() {
+ if (getVisibility() != View.VISIBLE) {
+ return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+ }
+ return super.getDescendantFocusability();
+ }
}
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
index 007ecf8..e8ca61f 100644
--- a/src/com/android/launcher2/AllAppsView.java
+++ b/src/com/android/launcher2/AllAppsView.java
@@ -23,9 +23,7 @@
public void zoomed(float zoom);
}
- public void setLauncher(Launcher launcher);
-
- public void setDragController(DragController dragger);
+ public void setup(Launcher launcher, DragController dragController);
public void zoom(float zoom, boolean animate);
@@ -41,6 +39,9 @@
public void updateApps(ArrayList<ApplicationInfo> list);
+ // Resets the AllApps page to the front
+ public void reset();
+
public void dumpState();
public void surrender();
diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java
index 2b2662f..4390c59 100644
--- a/src/com/android/launcher2/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher2/AppWidgetResizeFrame.java
@@ -18,6 +18,8 @@
private ItemInfo mItemInfo;
private LauncherAppWidgetHostView mWidgetView;
private CellLayout mCellLayout;
+ private DragLayer mDragLayer;
+ private Workspace mWorkspace;
private ImageView mLeftHandle;
private ImageView mRightHandle;
private ImageView mTopHandle;
@@ -57,7 +59,7 @@
public static final int BOTTOM = 3;
public AppWidgetResizeFrame(Context context, ItemInfo itemInfo,
- LauncherAppWidgetHostView widgetView, CellLayout cellLayout) {
+ LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
super(context);
mContext = context;
@@ -65,6 +67,8 @@
mCellLayout = cellLayout;
mWidgetView = widgetView;
mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
+ mDragLayer = dragLayer;
+ mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
int[] result = mCellLayout.rectToCell(info.minWidth, info.minHeight, null);
@@ -150,7 +154,7 @@
mDeltaX = Math.max(-mBaselineX, deltaX);
mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
} else if (mRightBorderActive) {
- mDeltaX = Math.min(mCellLayout.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
+ mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
}
@@ -158,7 +162,7 @@
mDeltaY = Math.max(-mBaselineY, deltaY);
mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
} else if (mBottomBorderActive) {
- mDeltaY = Math.min(mCellLayout.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
+ mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
}
}
@@ -168,7 +172,8 @@
*/
public void visualizeResizeForDelta(int deltaX, int deltaY) {
updateDeltas(deltaX, deltaY);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+ DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+
if (mLeftBorderActive) {
lp.x = mBaselineX + mDeltaX;
lp.width = mBaselineWidth - mDeltaX;
@@ -261,6 +266,7 @@
// Update the cells occupied by this widget
mCellLayout.markCellsAsOccupiedForView(mWidgetView);
+ mWidgetView.requestLayout();
}
/**
@@ -284,20 +290,22 @@
}
public void snapToWidget(boolean animate) {
- final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+ final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+ int xOffset = mCellLayout.getLeft() + mCellLayout.getLeftPadding() - mWorkspace.getScrollX();
+ int yOffset = mCellLayout.getTop() + mCellLayout.getTopPadding() - mWorkspace.getScrollY();
int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding;
int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding;
- int newX = mWidgetView.getLeft() - mBackgroundPadding;
- int newY = mWidgetView.getTop() - mBackgroundPadding;
+ int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset;
+ int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset;
// We need to make sure the frame stays within the bounds of the CellLayout
if (newY < 0) {
newHeight -= -newY;
newY = 0;
}
- if (newY + newHeight > mCellLayout.getHeight()) {
- newHeight -= newY + newHeight - mCellLayout.getHeight();
+ if (newY + newHeight > mDragLayer.getHeight()) {
+ newHeight -= newY + newHeight - mDragLayer.getHeight();
}
if (!animate) {
diff --git a/src/com/android/launcher2/ApplicationInfoDropTarget.java b/src/com/android/launcher2/ApplicationInfoDropTarget.java
index 78a9d2d..f42aaf5 100644
--- a/src/com/android/launcher2/ApplicationInfoDropTarget.java
+++ b/src/com/android/launcher2/ApplicationInfoDropTarget.java
@@ -50,7 +50,7 @@
int colour = getContext().getResources().getColor(R.color.app_info_filter);
mHoverPaint.setColorFilter(new PorterDuffColorFilter(colour, PorterDuff.Mode.SRC_ATOP));
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
// For the application info drop target, we just ignore the left padding since we don't want
// to overlap with the delete zone padding
int tb = getResources().getDimensionPixelSize(
@@ -162,10 +162,13 @@
// Fade in the overlapping views
if (mOverlappingViews != null) {
for (View view : mOverlappingViews) {
- ObjectAnimator oa = ObjectAnimator.ofFloat(view, "alpha", 1.0f);
- oa.setDuration(sFadeInAnimationDuration);
- mFadeAnimator.play(oa);
- view.setVisibility(VISIBLE);
+ // Check whether the views are enabled first, before trying to fade them in
+ if (view.isEnabled()) {
+ ObjectAnimator oa = ObjectAnimator.ofFloat(view, "alpha", 1.0f);
+ oa.setDuration(sFadeInAnimationDuration);
+ mFadeAnimator.play(oa);
+ view.setVisibility(VISIBLE);
+ }
}
}
mFadeAnimator.start();
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
new file mode 100644
index 0000000..14e051c
--- /dev/null
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -0,0 +1,1085 @@
+/*
+ * 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.launcher2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.app.WallpaperManager;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.LruCache;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.launcher.R;
+
+public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
+ AllAppsView, View.OnClickListener, DragSource {
+ static final String LOG_TAG = "AppsCustomizePagedView";
+
+ /**
+ * The different content types that this paged view can show.
+ */
+ public enum ContentType {
+ Applications,
+ Widgets,
+ Wallpapers
+ }
+
+ // Refs
+ private Launcher mLauncher;
+ private DragController mDragController;
+ private final LayoutInflater mLayoutInflater;
+ private final PackageManager mPackageManager;
+
+ // Content
+ private ContentType mContentType;
+ private ArrayList<ApplicationInfo> mApps;
+ private List<Object> mWidgets;
+ private List<ResolveInfo> mWallpapers;
+
+ // Caching
+ private Drawable mDefaultWidgetBackground;
+ private final int sWidgetPreviewCacheSize = 1 * 1024 * 1024; // 1 MiB
+ private LruCache<Object, Bitmap> mWidgetPreviewCache;
+ private IconCache mIconCache;
+
+ // Dimens
+ private int mContentWidth;
+ private int mMaxWidgetSpan, mMinWidgetSpan;
+ private int mCellWidthGap, mCellHeightGap;
+ private int mWidgetCountX, mWidgetCountY;
+ private int mWallpaperCountX, mWallpaperCountY;
+ private final int mWidgetPreviewIconPaddedDimension;
+ private final float sWidgetPreviewIconPaddingPercentage = 0.25f;
+ private PagedViewCellLayout mWidgetSpacingLayout;
+
+ // Animations
+ private final float ANIMATION_SCALE = 0.5f;
+ private final int TRANSLATE_ANIM_DURATION = 400;
+ private final int DROP_ANIM_DURATION = 200;
+
+ public AppsCustomizePagedView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mLayoutInflater = LayoutInflater.from(context);
+ mPackageManager = context.getPackageManager();
+ mContentType = ContentType.Applications;
+ mApps = new ArrayList<ApplicationInfo>();
+ mWidgets = new ArrayList<Object>();
+ mWallpapers = new ArrayList<ResolveInfo>();
+ mIconCache = ((LauncherApplication) context.getApplicationContext()).getIconCache();
+ mWidgetPreviewCache = new LruCache<Object, Bitmap>(sWidgetPreviewCacheSize) {
+ protected int sizeOf(Object key, Bitmap value) {
+ return value.getByteCount();
+ }
+ };
+
+ // Save the default widget preview background
+ Resources resources = context.getResources();
+ mDefaultWidgetBackground = resources.getDrawable(R.drawable.default_widget_preview);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedView, 0, 0);
+ mCellCountX = a.getInt(R.styleable.PagedView_cellCountX, 6);
+ mCellCountY = a.getInt(R.styleable.PagedView_cellCountY, 4);
+ a.recycle();
+ a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
+ mCellWidthGap =
+ a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellWidthGap, 10);
+ mCellHeightGap =
+ a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellHeightGap, 10);
+ mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
+ mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
+ mWallpaperCountX = a.getInt(R.styleable.AppsCustomizePagedView_wallpaperCountX, 2);
+ mWallpaperCountY = a.getInt(R.styleable.AppsCustomizePagedView_wallpaperCountY, 2);
+ a.recycle();
+
+ // Create a dummy page that we can use to approximate the cell dimensions of widgets and
+ // the content width (to be used by our parent)
+ mWidgetSpacingLayout = new PagedViewCellLayout(context);
+ setupPage(mWidgetSpacingLayout);
+ mContentWidth = mWidgetSpacingLayout.getContentWidth();
+
+ // The max widget span is the length N, such that NxN is the largest bounds that the widget
+ // preview can be before applying the widget scaling
+ mMinWidgetSpan = 1;
+ mMaxWidgetSpan = 3;
+
+ // The padding on the non-matched dimension for the default widget preview icons
+ // (top + bottom)
+ int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
+ mWidgetPreviewIconPaddedDimension =
+ (int) (iconSize * (1 + (2 * sWidgetPreviewIconPaddingPercentage)));
+ }
+
+ @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 onPackagesUpdated() {
+ // Get the list of widgets and shortcuts
+ mWidgets.clear();
+ mWidgets.addAll(AppWidgetManager.getInstance(mLauncher).getInstalledProviders());
+ Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+ mWidgets.addAll(mPackageManager.queryIntentActivities(shortcutsIntent, 0));
+ Collections.sort(mWidgets,
+ new LauncherModel.WidgetAndShortcutNameComparator(mPackageManager));
+
+ // Get the list of wallpapers
+ Intent wallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
+ mWallpapers = mPackageManager.queryIntentActivities(wallpapersIntent,
+ PackageManager.GET_META_DATA);
+ Collections.sort(mWallpapers,
+ new LauncherModel.ShortcutNameComparator(mPackageManager));
+ }
+
+ /**
+ * Animates the given item onto the center of a home screen, and then scales the item to
+ * look as though it's disappearing onto that screen.
+ */
+ private void animateItemOntoScreen(View dragView,
+ final CellLayout layout, final ItemInfo info) {
+ // On the phone, we only want to fade the widget preview out
+ float[] position = new float[2];
+ position[0] = layout.getWidth() / 2;
+ position[1] = layout.getHeight() / 2;
+
+ mLauncher.getWorkspace().mapPointFromChildToSelf(layout, position);
+
+ int dragViewWidth = dragView.getMeasuredWidth();
+ int dragViewHeight = dragView.getMeasuredHeight();
+ float heightOffset = 0;
+ float widthOffset = 0;
+
+ if (dragView instanceof ImageView) {
+ Drawable d = ((ImageView) dragView).getDrawable();
+ int width = d.getIntrinsicWidth();
+ int height = d.getIntrinsicHeight();
+
+ if ((1.0 * width / height) >= (1.0f * dragViewWidth) / dragViewHeight) {
+ float f = (dragViewWidth / (width * 1.0f));
+ heightOffset = ANIMATION_SCALE * (dragViewHeight - f * height) / 2;
+ } else {
+ float f = (dragViewHeight / (height * 1.0f));
+ widthOffset = ANIMATION_SCALE * (dragViewWidth - f * width) / 2;
+ }
+ }
+ final float toX = position[0] - dragView.getMeasuredWidth() / 2 + widthOffset;
+ final float toY = position[1] - dragView.getMeasuredHeight() / 2 + heightOffset;
+
+ final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+ final View dragCopy = dragLayer.createDragView(dragView);
+ dragCopy.setAlpha(1.0f);
+
+ // Translate the item to the center of the appropriate home screen
+ animateIntoPosition(dragCopy, toX, toY, null);
+
+ // The drop-onto-screen animation begins a bit later, but ends at the same time.
+ final int startDelay = TRANSLATE_ANIM_DURATION - DROP_ANIM_DURATION;
+
+ // Scale down the icon and fade out the alpha
+ animateDropOntoScreen(dragCopy, info, DROP_ANIM_DURATION, startDelay);
+ }
+
+ /**
+ * Animation which scales the view down and animates its alpha, making it appear to disappear
+ * onto a home screen.
+ */
+ private void animateDropOntoScreen(
+ final View view, final ItemInfo info, int duration, int delay) {
+ final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+ final CellLayout layout = mLauncher.getWorkspace().getCurrentDropLayout();
+
+ ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view,
+ PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f),
+ PropertyValuesHolder.ofFloat("scaleX", ANIMATION_SCALE),
+ PropertyValuesHolder.ofFloat("scaleY", ANIMATION_SCALE));
+ anim.setInterpolator(new LinearInterpolator());
+ if (delay > 0) {
+ anim.setStartDelay(delay);
+ }
+ anim.setDuration(duration);
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ dragLayer.removeView(view);
+ mLauncher.addExternalItemToScreen(info, layout);
+ info.dropPos = null;
+ }
+ });
+ anim.start();
+ }
+
+ /**
+ * Animates the x,y position of the view, and optionally execute a Runnable on animation end.
+ */
+ private void animateIntoPosition(
+ View view, float toX, float toY, final Runnable endRunnable) {
+ ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view,
+ PropertyValuesHolder.ofFloat("x", toX),
+ PropertyValuesHolder.ofFloat("y", toY));
+ anim.setInterpolator(new DecelerateInterpolator(2.5f));
+ anim.setDuration(TRANSLATE_ANIM_DURATION);
+ if (endRunnable != null) {
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endRunnable.run();
+ }
+ });
+ }
+ anim.start();
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v instanceof PagedViewIcon) {
+ // Animate some feedback to the click
+ final ApplicationInfo appInfo = (ApplicationInfo) v.getTag();
+ animateClickFeedback(v, new Runnable() {
+ @Override
+ public void run() {
+ mLauncher.startActivitySafely(appInfo.intent, appInfo);
+ }
+ });
+ } else if (v instanceof PagedViewWidget) {
+ final ResolveInfo info = (ResolveInfo) v.getTag();
+ if (mWallpapers.contains(info)) {
+ // Start the wallpaper picker
+ animateClickFeedback(v, new Runnable() {
+ @Override
+ public void run() {
+ // add the shortcut
+ Intent createWallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
+ ComponentName name = new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name);
+ createWallpapersIntent.setComponent(name);
+ mLauncher.processWallpaper(createWallpapersIntent);
+ }
+ });
+ } else {
+ // Add the widget to the current workspace screen
+ Workspace w = mLauncher.getWorkspace();
+ int currentWorkspaceScreen = mLauncher.getCurrentWorkspaceScreen();
+ final CellLayout cl = (CellLayout) w.getChildAt(currentWorkspaceScreen);
+ final View dragView = v.findViewById(R.id.widget_preview);
+ final ItemInfo itemInfo = (ItemInfo) v.getTag();
+ animateClickFeedback(v, new Runnable() {
+ @Override
+ public void run() {
+ cl.calculateSpans(itemInfo);
+ if (cl.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY)) {
+ if (LauncherApplication.isScreenLarge()) {
+ animateItemOntoScreen(dragView, cl, itemInfo);
+ } else {
+ mLauncher.addExternalItemToScreen(itemInfo, cl);
+ itemInfo.dropPos = null;
+ }
+
+ // Hide the pane so we can see the workspace we dropped on
+ mLauncher.showWorkspace(true);
+ } else {
+ mLauncher.showOutOfSpaceMessage();
+ }
+ }
+ });
+ }
+ }
+ }
+
+ /*
+ * PagedViewWithDraggableItems implementation
+ */
+ @Override
+ protected void determineDraggingStart(android.view.MotionEvent ev) {
+ // Disable dragging by pulling an app down for now.
+ }
+ private void beginDraggingApplication(View v) {
+ // Make a copy of the ApplicationInfo
+ ApplicationInfo appInfo = new ApplicationInfo((ApplicationInfo) v.getTag());
+
+ // Show the uninstall button if the app is uninstallable.
+ if ((appInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) != 0) {
+ DeleteZone allAppsDeleteZone = (DeleteZone)
+ mLauncher.findViewById(R.id.all_apps_delete_zone);
+ allAppsDeleteZone.setDragAndDropEnabled(true);
+
+ if ((appInfo.flags & ApplicationInfo.UPDATED_SYSTEM_APP_FLAG) != 0) {
+ allAppsDeleteZone.setText(R.string.delete_zone_label_all_apps_system_app);
+ } else {
+ allAppsDeleteZone.setText(R.string.delete_zone_label_all_apps);
+ }
+ }
+
+ // Show the info button
+ ApplicationInfoDropTarget allAppsInfoButton =
+ (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target);
+ allAppsInfoButton.setDragAndDropEnabled(true);
+
+ // Compose the drag image (top compound drawable, index is 1)
+ final TextView tv = (TextView) v;
+ final Drawable icon = tv.getCompoundDrawables()[1];
+ Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ c.translate((v.getWidth() - icon.getIntrinsicWidth()) / 2, v.getPaddingTop());
+ icon.draw(c);
+
+ // Compose the visible rect of the drag image
+ Rect dragRect = null;
+ if (v instanceof TextView) {
+ int iconSize = getResources().getDimensionPixelSize(R.dimen.app_icon_size);
+ int top = v.getPaddingTop();
+ int left = (b.getWidth() - iconSize) / 2;
+ int right = left + iconSize;
+ int bottom = top + iconSize;
+ dragRect = new Rect(left, top, right, bottom);
+ }
+
+ // Start the drag
+ mLauncher.lockScreenOrientation();
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
+ mDragController.startDrag(v, b, this, appInfo, DragController.DRAG_ACTION_COPY, dragRect);
+ b.recycle();
+ }
+ private void beginDraggingWidget(View v) {
+ // Get the widget preview as the drag representation
+ ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
+ PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
+
+ // Compose the drag image
+ Bitmap b;
+ Drawable preview = image.getDrawable();
+ int w = preview.getIntrinsicWidth();
+ int h = preview.getIntrinsicHeight();
+ if (createItemInfo instanceof PendingAddWidgetInfo) {
+ PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
+ int[] spanXY = CellLayout.rectToCell(getResources(),
+ createWidgetInfo.minWidth, createWidgetInfo.minHeight, null);
+ createItemInfo.spanX = spanXY[0];
+ createItemInfo.spanY = spanXY[1];
+
+ b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+ renderDrawableToBitmap(preview, b, 0, 0, w, h, 1, 1);
+ } else {
+ // Workaround for the fact that we don't keep the original ResolveInfo associated with
+ // the shortcut around. To get the icon, we just render the preview image (which has
+ // the shortcut icon) to a new drag bitmap that clips the non-icon space.
+ b = Bitmap.createBitmap(mWidgetPreviewIconPaddedDimension,
+ mWidgetPreviewIconPaddedDimension, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ preview.draw(c);
+ createItemInfo.spanX = createItemInfo.spanY = 1;
+ }
+
+ // Start the drag
+ mLauncher.lockScreenOrientation();
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(createItemInfo.spanX,
+ createItemInfo.spanY, b);
+ mDragController.startDrag(image, b, this, createItemInfo,
+ DragController.DRAG_ACTION_COPY, null);
+ b.recycle();
+ }
+ @Override
+ protected boolean beginDragging(View v) {
+ if (!super.beginDragging(v)) return false;
+
+ // Hide the pane so that the user can drop onto the workspace, we must do this first,
+ // due to how the drop target layout is computed when we start dragging to the workspace.
+ mLauncher.showWorkspace(true);
+
+ if (v instanceof PagedViewIcon) {
+ beginDraggingApplication(v);
+ } else if (v instanceof PagedViewWidget) {
+ beginDraggingWidget(v);
+ }
+
+ return true;
+ }
+ private void endDragging(boolean success) {
+ post(new Runnable() {
+ // Once the drag operation has fully completed, hence the post, we want to disable the
+ // deleteZone and the appInfoButton in all apps, and re-enable the instance which
+ // live in the workspace
+ public void run() {
+ // if onDestroy was called on Launcher, we might have already deleted the
+ // all apps delete zone / info button, so check if they are null
+ DeleteZone allAppsDeleteZone =
+ (DeleteZone) mLauncher.findViewById(R.id.all_apps_delete_zone);
+ ApplicationInfoDropTarget allAppsInfoButton =
+ (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target);
+
+ if (allAppsDeleteZone != null) allAppsDeleteZone.setDragAndDropEnabled(false);
+ if (allAppsInfoButton != null) allAppsInfoButton.setDragAndDropEnabled(false);
+ }
+ });
+ mLauncher.getWorkspace().onDragStopped(success);
+ mLauncher.unlockScreenOrientation();
+ }
+
+ /*
+ * DragSource implementation
+ */
+ @Override
+ public void onDragViewVisible() {}
+ @Override
+ public void onDropCompleted(View target, Object dragInfo, boolean success) {
+ endDragging(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) dragInfo;
+ if (layout != null) {
+ layout.calculateSpans(itemInfo);
+ showOutOfSpaceMessage =
+ !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
+ }
+ }
+ // TODO-APPS_CUSTOMIZE: We need to handle this for folders as well later.
+ if (showOutOfSpaceMessage) {
+ mLauncher.showOutOfSpaceMessage();
+ }
+ }
+ }
+
+ public void setContentType(ContentType type) {
+ mContentType = type;
+ setCurrentPage(0);
+ invalidatePageData();
+ }
+
+ /*
+ * Apps PagedView implementation
+ */
+ private void setVisibilityOnChildren(ViewGroup layout, int visibility) {
+ int childCount = layout.getChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ layout.getChildAt(i).setVisibility(visibility);
+ }
+ }
+ private void setupPage(PagedViewCellLayout layout) {
+ layout.setCellCount(mCellCountX, mCellCountY);
+ layout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap);
+ layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
+ mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
+
+ // 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. That said, we already know the
+ // expected page width, so we can actually optimize by hiding all the TextView-based
+ // children that are expensive to measure, and let that happen naturally later.
+ setVisibilityOnChildren(layout, View.GONE);
+ int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
+ int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
+ layout.setMinimumWidth(getPageContentWidth());
+ layout.measure(widthSpec, heightSpec);
+ setVisibilityOnChildren(layout, View.VISIBLE);
+ }
+ public void syncAppsPages() {
+ // Ensure that we have the right number of pages
+ Context context = getContext();
+ int numPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
+ for (int i = 0; i < numPages; ++i) {
+ PagedViewCellLayout layout = new PagedViewCellLayout(context);
+ setupPage(layout);
+ addView(layout);
+ }
+ }
+ public void syncAppsPageItems(int page) {
+ // ensure that we have the right number of items on the pages
+ int numPages = getPageCount();
+ int numCells = mCellCountX * mCellCountY;
+ int startIndex = page * numCells;
+ int endIndex = Math.min(startIndex + numCells, mApps.size());
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
+ layout.removeAllViewsOnPage();
+ for (int i = startIndex; i < endIndex; ++i) {
+ ApplicationInfo info = mApps.get(i);
+ PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate(
+ R.layout.apps_customize_application, layout, false);
+ icon.applyFromApplicationInfo(
+ info, mPageViewIconCache, true, isHardwareAccelerated() && (numPages > 1));
+ icon.setOnClickListener(this);
+ icon.setOnLongClickListener(this);
+ icon.setOnTouchListener(this);
+
+ int index = i - startIndex;
+ int x = index % mCellCountX;
+ int y = index / mCellCountX;
+ layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1),
+ isHardwareAccelerated() && (numPages > 1));
+ }
+ }
+ /*
+ * Widgets PagedView implementation
+ */
+ private void setupPage(PagedViewGridLayout layout) {
+ layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
+ mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
+
+ // 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. That said, we already know the
+ // expected page width, so we can actually optimize by hiding all the TextView-based
+ // children that are expensive to measure, and let that happen naturally later.
+ setVisibilityOnChildren(layout, View.GONE);
+ int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
+ int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
+ layout.setMinimumWidth(getPageContentWidth());
+ layout.measure(widthSpec, heightSpec);
+ setVisibilityOnChildren(layout, View.VISIBLE);
+ }
+ private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h,
+ float scaleX, float scaleY) {
+ Canvas c = new Canvas();
+ if (bitmap != null) c.setBitmap(bitmap);
+ c.save();
+ c.scale(scaleX, scaleY);
+ Rect oldBounds = d.copyBounds();
+ d.setBounds(x, y, x + w, y + h);
+ d.draw(c);
+ d.setBounds(oldBounds); // Restore the bounds
+ c.restore();
+ }
+ private FastBitmapDrawable getShortcutPreview(ResolveInfo info, int cellWidth, int cellHeight) {
+ // Return the cached version if necessary
+ Bitmap cachedBitmap = mWidgetPreviewCache.get(info);
+ if (cachedBitmap != null) {
+ return new FastBitmapDrawable(cachedBitmap);
+ }
+
+ Resources resources = mLauncher.getResources();
+ int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
+ // We only need to make it wide enough so as not allow the preview to be scaled
+ int expectedWidth = cellWidth;
+ int expectedHeight = mWidgetPreviewIconPaddedDimension;
+ int offset = (int) (iconSize * sWidgetPreviewIconPaddingPercentage);
+
+ // Render the icon
+ Bitmap preview = Bitmap.createBitmap(expectedWidth, expectedHeight, Config.ARGB_8888);
+ Drawable icon = mIconCache.getFullResIcon(info, mPackageManager);
+ renderDrawableToBitmap(mDefaultWidgetBackground, preview, 0, 0,
+ mWidgetPreviewIconPaddedDimension, mWidgetPreviewIconPaddedDimension, 1f, 1f);
+ renderDrawableToBitmap(icon, preview, offset, offset, iconSize, iconSize, 1f, 1f);
+ FastBitmapDrawable iconDrawable = new FastBitmapDrawable(preview);
+ iconDrawable.setBounds(0, 0, expectedWidth, expectedHeight);
+ mWidgetPreviewCache.put(info, preview);
+ return iconDrawable;
+ }
+ private FastBitmapDrawable getWidgetPreview(AppWidgetProviderInfo info, int cellHSpan,
+ int cellVSpan, int cellWidth, int cellHeight) {
+ // Return the cached version if necessary
+ Bitmap cachedBitmap = mWidgetPreviewCache.get(info);
+ if (cachedBitmap != null) {
+ return new FastBitmapDrawable(cachedBitmap);
+ }
+
+ // Calculate the size of the drawable
+ cellHSpan = Math.max(mMinWidgetSpan, Math.min(mMaxWidgetSpan, cellHSpan));
+ cellVSpan = Math.max(mMinWidgetSpan, Math.min(mMaxWidgetSpan, cellVSpan));
+ int expectedWidth = mWidgetSpacingLayout.estimateCellWidth(cellHSpan);
+ int expectedHeight = mWidgetSpacingLayout.estimateCellHeight(cellVSpan);
+
+ // Scale down the bitmap to fit the space
+ float widgetPreviewScale = (float) cellWidth / expectedWidth;
+ expectedWidth = (int) (widgetPreviewScale * expectedWidth);
+ expectedHeight = (int) (widgetPreviewScale * expectedHeight);
+
+ // Load the preview image if possible
+ String packageName = info.provider.getPackageName();
+ Drawable drawable = null;
+ FastBitmapDrawable newDrawable = null;
+ if (info.previewImage != 0) {
+ drawable = mPackageManager.getDrawable(packageName, info.previewImage, null);
+ if (drawable == null) {
+ Log.w(LOG_TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+ + " for provider: " + info.provider);
+ } else {
+ // Scale down the preview to the dimensions we want
+ int imageWidth = drawable.getIntrinsicWidth();
+ int imageHeight = drawable.getIntrinsicHeight();
+ float aspect = (float) imageWidth / imageHeight;
+ int newWidth = imageWidth;
+ int newHeight = imageHeight;
+ if (aspect > 1f) {
+ newWidth = expectedWidth;
+ newHeight = (int) (imageHeight * ((float) expectedWidth / imageWidth));
+ } else {
+ newHeight = expectedHeight;
+ newWidth = (int) (imageWidth * ((float) expectedHeight / imageHeight));
+ }
+
+ Bitmap preview = Bitmap.createBitmap(newWidth, newHeight, Config.ARGB_8888);
+ renderDrawableToBitmap(drawable, preview, 0, 0, newWidth, newHeight, 1f, 1f);
+ newDrawable = new FastBitmapDrawable(preview);
+ newDrawable.setBounds(0, 0, newWidth, newHeight);
+ mWidgetPreviewCache.put(info, preview);
+ }
+ }
+
+ // Generate a preview image if we couldn't load one
+ if (drawable == null) {
+ Resources resources = mLauncher.getResources();
+ int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
+
+ // Specify the dimensions of the bitmap
+ if (info.minWidth >= info.minHeight) {
+ expectedWidth = cellWidth;
+ expectedHeight = mWidgetPreviewIconPaddedDimension;
+ } else {
+ // Note that in vertical widgets, we might not have enough space due to the text
+ // label, so be conservative and use the width as a height bound
+ expectedWidth = mWidgetPreviewIconPaddedDimension;
+ expectedHeight = cellWidth;
+ }
+
+ Bitmap preview = Bitmap.createBitmap(expectedWidth, expectedHeight, Config.ARGB_8888);
+ renderDrawableToBitmap(mDefaultWidgetBackground, preview, 0, 0, expectedWidth,
+ expectedHeight, 1f,1f);
+
+ // Draw the icon in the top left corner
+ try {
+ Drawable icon = null;
+ if (info.icon > 0) icon = mPackageManager.getDrawable(packageName, info.icon, null);
+ if (icon == null) icon = resources.getDrawable(R.drawable.ic_launcher_application);
+
+ int offset = (int) (iconSize * sWidgetPreviewIconPaddingPercentage);
+ renderDrawableToBitmap(icon, preview, offset, offset, iconSize, iconSize, 1f, 1f);
+ } catch (Resources.NotFoundException e) {}
+
+ newDrawable = new FastBitmapDrawable(preview);
+ newDrawable.setBounds(0, 0, expectedWidth, expectedHeight);
+ mWidgetPreviewCache.put(info, preview);
+ }
+ return newDrawable;
+ }
+ public void syncWidgetPages() {
+ // Ensure that we have the right number of pages
+ Context context = getContext();
+ int numWidgetsPerPage = mWidgetCountX * mWidgetCountY;
+ int numPages = (int) Math.ceil(mWidgets.size() / (float) numWidgetsPerPage);
+ for (int i = 0; i < numPages; ++i) {
+ PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
+ mWidgetCountY);
+ setupPage(layout);
+ addView(layout);
+ }
+ }
+ public void syncWidgetPageItems(int page) {
+ PagedViewGridLayout layout = (PagedViewGridLayout) getChildAt(page);
+ layout.removeAllViews();
+
+ // Calculate the dimensions of each cell we are giving to each widget
+ int numWidgetsPerPage = mWidgetCountX * mWidgetCountY;
+ int offset = page * numWidgetsPerPage;
+ int cellWidth = ((mWidgetSpacingLayout.getContentWidth() - mPageLayoutWidthGap
+ - ((mWidgetCountX - 1) * mCellWidthGap)) / mWidgetCountX);
+ int cellHeight = ((mWidgetSpacingLayout.getContentHeight() - mPageLayoutHeightGap
+ - ((mWidgetCountY - 1) * mCellHeightGap)) / mWidgetCountY);
+ for (int i = 0; i < Math.min(numWidgetsPerPage, mWidgets.size() - offset); ++i) {
+ Object rawInfo = mWidgets.get(offset + i);
+ PendingAddItemInfo createItemInfo = null;
+ PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
+ R.layout.apps_customize_widget, layout, false);
+ if (rawInfo instanceof AppWidgetProviderInfo) {
+ // Fill in the widget information
+ AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
+ createItemInfo = new PendingAddWidgetInfo(info, null, null);
+ final int[] cellSpans = CellLayout.rectToCell(getResources(), info.minWidth,
+ info.minHeight, null);
+ FastBitmapDrawable preview = getWidgetPreview(info, cellSpans[0], cellSpans[1],
+ cellWidth, cellHeight);
+ widget.applyFromAppWidgetProviderInfo(info, preview, -1, cellSpans, null, false);
+ widget.setTag(createItemInfo);
+ } else if (rawInfo instanceof ResolveInfo) {
+ // Fill in the shortcuts information
+ ResolveInfo info = (ResolveInfo) rawInfo;
+ createItemInfo = new PendingAddItemInfo();
+ createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+ createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name);
+ FastBitmapDrawable preview = getShortcutPreview(info, cellWidth, cellHeight);
+ widget.applyFromResolveInfo(mPackageManager, info, preview, null, false);
+ widget.setTag(createItemInfo);
+ }
+ widget.setOnClickListener(this);
+ widget.setOnLongClickListener(this);
+ widget.setOnTouchListener(this);
+
+ // Layout each widget
+ int ix = i % mWidgetCountX;
+ int iy = i / mWidgetCountX;
+ PagedViewGridLayout.LayoutParams lp = new PagedViewGridLayout.LayoutParams(cellWidth,
+ cellHeight);
+ lp.leftMargin = (ix * cellWidth) + (ix * mCellWidthGap);
+ lp.topMargin = (iy * cellHeight) + (iy * mCellHeightGap);
+ layout.addView(widget, lp);
+ }
+ }
+
+ /*
+ * This method fetches an xml file specified in the manifest identified by
+ * WallpaperManager.WALLPAPER_PREVIEW_META_DATA). The xml file specifies
+ * an image which will be used as the wallpaper preview for an activity
+ * which responds to ACTION_SET_WALLPAPER. This image is returned and used
+ * in the customize drawer.
+ */
+ private Drawable parseWallpaperPreviewXml(ResolveInfo ri) {
+ ActivityInfo activityInfo = ri.activityInfo;
+ XmlResourceParser parser = null;
+ ComponentName component = new ComponentName(ri.activityInfo.packageName,
+ ri.activityInfo.name);
+ try {
+ parser = activityInfo.loadXmlMetaData(mPackageManager,
+ WallpaperManager.WALLPAPER_PREVIEW_META_DATA);
+ if (parser == null) {
+ Slog.w(LOG_TAG, "No " + WallpaperManager.WALLPAPER_PREVIEW_META_DATA
+ + " meta-data for " + "wallpaper provider '" + component + '\'');
+ return null;
+ }
+
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ // drain whitespace, comments, etc.
+ }
+
+ String nodeName = parser.getName();
+ if (!"wallpaper-preview".equals(nodeName)) {
+ Slog.w(LOG_TAG, "Meta-data does not start with wallpaper-preview tag for "
+ + "wallpaper provider '" + component + '\'');
+ return null;
+ }
+
+ // If metaData was null, we would have returned earlier when getting
+ // the parser No need to do the check here
+ Resources res = mPackageManager.getResourcesForApplication(
+ activityInfo.applicationInfo);
+
+ TypedArray sa = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.WallpaperPreviewInfo);
+
+ TypedValue value = sa.peekValue(
+ com.android.internal.R.styleable.WallpaperPreviewInfo_staticWallpaperPreview);
+ if (value == null) return null;
+
+ return res.getDrawable(value.resourceId);
+ } catch (Exception e) {
+ Slog.w(LOG_TAG, "XML parsing failed for wallpaper provider '" + component + '\'', e);
+ return null;
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+ private FastBitmapDrawable getWallpaperPreview(ResolveInfo info, int cellWidth, int cellHeight){
+ // Return the cached version if necessary
+ Bitmap cachedBitmap = mWidgetPreviewCache.get(info);
+ if (cachedBitmap != null) {
+ return new FastBitmapDrawable(cachedBitmap);
+ }
+
+ // Get the preview
+ Resources resources = getContext().getResources();
+ Drawable wallpaperPreview = parseWallpaperPreviewXml(info);
+ Drawable wallpaperIcon = null;
+ int expectedWidth;
+ int expectedHeight;
+ if (wallpaperPreview != null) {
+ expectedWidth = wallpaperPreview.getIntrinsicWidth();
+ expectedHeight = wallpaperPreview.getIntrinsicHeight();
+ } else {
+ wallpaperPreview = mDefaultWidgetBackground;
+ expectedWidth = expectedHeight = Math.min(cellWidth, cellHeight);
+
+ // Draw the icon in the top left corner
+ String packageName = info.activityInfo.packageName;
+ try {
+ if (info.icon > 0) {
+ wallpaperIcon = mPackageManager.getDrawable(packageName, info.icon, null);
+ }
+ if (wallpaperIcon == null) {
+ wallpaperIcon = resources.getDrawable(R.drawable.ic_launcher_application);
+ }
+ } catch (Resources.NotFoundException e) {}
+ }
+
+ // Create the bitmap
+ Bitmap preview = Bitmap.createBitmap(expectedWidth, expectedHeight, Config.ARGB_8888);
+ renderDrawableToBitmap(wallpaperPreview, preview, 0, 0, expectedWidth, expectedHeight,
+ 1f, 1f);
+ if (wallpaperIcon != null) {
+ int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
+ int offset = (int) (iconSize * sWidgetPreviewIconPaddingPercentage);
+ renderDrawableToBitmap(wallpaperIcon, preview, offset, offset, iconSize, iconSize,
+ 1f, 1f);
+ }
+
+ FastBitmapDrawable previewDrawable = new FastBitmapDrawable(preview);
+ previewDrawable.setBounds(0, 0, expectedWidth, expectedHeight);
+ mWidgetPreviewCache.put(info, preview);
+ return previewDrawable;
+ }
+ /*
+ * Wallpapers PagedView implementation
+ */
+ public void syncWallpaperPages() {
+ // Ensure that we have the right number of pages
+ Context context = getContext();
+ int numWidgetsPerPage = mWallpaperCountX * mWallpaperCountY;
+ int numPages = (int) Math.ceil(mWallpapers.size() / (float) numWidgetsPerPage);
+ for (int i = 0; i < numPages; ++i) {
+ PagedViewGridLayout layout = new PagedViewGridLayout(context, mWallpaperCountX,
+ mWallpaperCountY);
+ setupPage(layout);
+ addView(layout);
+ }
+ }
+ public void syncWallpaperPageItems(int page) {
+ PagedViewGridLayout layout = (PagedViewGridLayout) getChildAt(page);
+ layout.removeAllViews();
+
+ // Calculate the dimensions of each cell we are giving to each widget
+ int numWidgetsPerPage = mWallpaperCountX * mWallpaperCountY;
+ int offset = page * numWidgetsPerPage;
+ int cellWidth = ((mWidgetSpacingLayout.getContentWidth() - mPageLayoutWidthGap
+ - ((mWallpaperCountX - 1) * mCellWidthGap)) / mWallpaperCountX);
+ int cellHeight = ((mWidgetSpacingLayout.getContentHeight() - mPageLayoutHeightGap
+ - ((mWallpaperCountY - 1) * mCellHeightGap)) / mWallpaperCountY);
+ for (int i = 0; i < Math.min(numWidgetsPerPage, mWallpapers.size() - offset); ++i) {
+ ResolveInfo info = mWallpapers.get(offset + i);
+ PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
+ R.layout.apps_customize_wallpaper, layout, false);
+
+ // Fill in the shortcuts information
+ FastBitmapDrawable preview = getWallpaperPreview(info, cellWidth, cellHeight);
+ widget.applyFromResolveInfo(mPackageManager, info, preview, null, false);
+ widget.setTag(info);
+ widget.setOnClickListener(this);
+ widget.setOnLongClickListener(this);
+ widget.setOnTouchListener(this);
+
+ // Layout each widget
+ int ix = i % mWallpaperCountX;
+ int iy = i / mWallpaperCountX;
+ PagedViewGridLayout.LayoutParams lp = new PagedViewGridLayout.LayoutParams(cellWidth,
+ cellHeight);
+ lp.leftMargin = (ix * cellWidth) + (ix * mCellWidthGap);
+ lp.topMargin = (iy * cellHeight) + (iy * mCellHeightGap);
+ layout.addView(widget, lp);
+ }
+ }
+
+ @Override
+ public void syncPages() {
+ removeAllViews();
+ switch (mContentType) {
+ case Applications:
+ syncAppsPages();
+ break;
+ case Widgets:
+ syncWidgetPages();
+ break;
+ case Wallpapers:
+ syncWallpaperPages();
+ break;
+ }
+ }
+ @Override
+ public void syncPageItems(int page) {
+ switch (mContentType) {
+ case Applications:
+ syncAppsPageItems(page);
+ break;
+ case Widgets:
+ syncWidgetPageItems(page);
+ break;
+ case Wallpapers:
+ syncWallpaperPageItems(page);
+ break;
+ }
+ }
+
+ /**
+ * Used by the parent to get the content width to set the tab bar to
+ * @return
+ */
+ public int getPageContentWidth() {
+ return mContentWidth;
+ }
+
+ /*
+ * AllAppsView implementation
+ */
+ @Override
+ public void setup(Launcher launcher, DragController dragController) {
+ mLauncher = launcher;
+ mDragController = dragController;
+ }
+ @Override
+ public void zoom(float zoom, boolean animate) {
+ // TODO-APPS_CUSTOMIZE: Call back to mLauncher.zoomed()
+ }
+ @Override
+ public boolean isVisible() {
+ return (getVisibility() == VISIBLE);
+ }
+ @Override
+ public boolean isAnimating() {
+ return false;
+ }
+ @Override
+ public void setApps(ArrayList<ApplicationInfo> list) {
+ mApps = list;
+ Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR);
+ invalidatePageData();
+ }
+ private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+ // We add it in place, in alphabetical order
+ int count = list.size();
+ for (int i = 0; i < count; ++i) {
+ ApplicationInfo info = list.get(i);
+ int index = Collections.binarySearch(mApps, info, LauncherModel.APP_NAME_COMPARATOR);
+ if (index < 0) {
+ mApps.add(-(index + 1), info);
+ }
+ }
+ }
+ @Override
+ public void addApps(ArrayList<ApplicationInfo> list) {
+ addAppsWithoutInvalidate(list);
+ invalidatePageData();
+ }
+ private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) {
+ ComponentName removeComponent = item.intent.getComponent();
+ int length = list.size();
+ for (int i = 0; i < length; ++i) {
+ ApplicationInfo info = list.get(i);
+ if (info.intent.getComponent().equals(removeComponent)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+ private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+ // loop through all the apps and remove apps that have the same component
+ int length = list.size();
+ for (int i = 0; i < length; ++i) {
+ ApplicationInfo info = list.get(i);
+ int removeIndex = findAppByComponent(mApps, info);
+ if (removeIndex > -1) {
+ mApps.remove(removeIndex);
+ mPageViewIconCache.removeOutline(new PagedViewIconCache.Key(info));
+ }
+ }
+ }
+ @Override
+ public void removeApps(ArrayList<ApplicationInfo> list) {
+ removeAppsWithoutInvalidate(list);
+ invalidatePageData();
+ }
+ @Override
+ public void updateApps(ArrayList<ApplicationInfo> list) {
+ // We remove and re-add the updated applications list because it's properties may have
+ // changed (ie. the title), and this will ensure that the items will be in their proper
+ // place in the list.
+ removeAppsWithoutInvalidate(list);
+ addAppsWithoutInvalidate(list);
+ invalidatePageData();
+ }
+ @Override
+ public void reset() {
+ if (mContentType != ContentType.Applications) {
+ // Reset to the first page of the Apps pane
+ AppsCustomizeTabHost tabs = (AppsCustomizeTabHost)
+ mLauncher.findViewById(R.id.apps_customize_pane);
+ tabs.setCurrentTabByTag(tabs.getTabTagForContentType(ContentType.Applications));
+ } else {
+ setCurrentPage(0);
+ invalidatePageData();
+ }
+ }
+ @Override
+ public void dumpState() {
+ // TODO: Dump information related to current list of Applications, Widgets, etc.
+ ApplicationInfo.dumpApplicationInfoList(LOG_TAG, "mApps", mApps);
+ dumpAppWidgetProviderInfoList(LOG_TAG, "mWidgets", mWidgets);
+ }
+ private void dumpAppWidgetProviderInfoList(String tag, String label,
+ List<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);
+ }
+ }
+ }
+ @Override
+ public void surrender() {
+ // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we
+ // should stop this now.
+ }
+}
diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java
new file mode 100644
index 0000000..e2d21b6
--- /dev/null
+++ b/src/com/android/launcher2/AppsCustomizeTabHost.java
@@ -0,0 +1,138 @@
+/*
+ * 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.launcher2;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TabHost;
+import android.widget.TextView;
+
+import com.android.launcher.R;
+
+public class AppsCustomizeTabHost extends TabHost implements LauncherTransitionable,
+ TabHost.OnTabChangeListener {
+ static final String LOG_TAG = "AppsCustomizeTabHost";
+
+ private static final String APPS_TAB_TAG = "APPS";
+ private static final String WIDGETS_TAB_TAG = "WIDGETS";
+ private static final String WALLPAPERS_TAB_TAG = "WALLPAPERS";
+
+ private final LayoutInflater mLayoutInflater;
+
+ public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mLayoutInflater = LayoutInflater.from(context);
+ }
+
+ /**
+ * Setup the tab host and create all necessary tabs.
+ */
+ @Override
+ protected void onFinishInflate() {
+ // Setup the tab host
+ setup();
+
+ final ViewGroup tabs = (ViewGroup) findViewById(com.android.internal.R.id.tabs);
+ final AppsCustomizePagedView content = (AppsCustomizePagedView)
+ findViewById(R.id.apps_customize_pane_content);
+ if (tabs == null || content == null) throw new Resources.NotFoundException();
+
+ // Configure the tabs content factory to return the same paged view (that we change the
+ // content filter on)
+ TabContentFactory contentFactory = new TabContentFactory() {
+ public View createTabContent(String tag) {
+ return content;
+ }
+ };
+
+ // Create the tabs
+ TextView tabView;
+ tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
+ tabView.setText(mContext.getString(R.string.all_apps_button_label));
+ addTab(newTabSpec(APPS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
+ tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
+ tabView.setText(mContext.getString(R.string.widgets_tab_label));
+ addTab(newTabSpec(WIDGETS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
+ tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
+ tabView.setText(mContext.getString(R.string.wallpapers_tab_label));
+ addTab(newTabSpec(WALLPAPERS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
+ setOnTabChangedListener(this);
+
+ // Set the width of the tab bar to match the content (for now)
+ tabs.getLayoutParams().width = content.getPageContentWidth();
+ }
+
+ @Override
+ public void onTabChanged(String tabId) {
+ final AppsCustomizePagedView content = (AppsCustomizePagedView)
+ findViewById(R.id.apps_customize_pane_content);
+ content.setContentType(getContentTypeForTabTag(tabId));
+ }
+
+ /**
+ * Returns the content type for the specified tab tag.
+ */
+ public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
+ if (tag.equals(APPS_TAB_TAG)) {
+ return AppsCustomizePagedView.ContentType.Applications;
+ } else if (tag.equals(WIDGETS_TAB_TAG)) {
+ return AppsCustomizePagedView.ContentType.Widgets;
+ } else if (tag.equals(WALLPAPERS_TAB_TAG)) {
+ return AppsCustomizePagedView.ContentType.Wallpapers;
+ }
+ return AppsCustomizePagedView.ContentType.Applications;
+ }
+
+ /**
+ * Returns the tab tag for a given content type.
+ */
+ public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
+ if (type == AppsCustomizePagedView.ContentType.Applications) {
+ return APPS_TAB_TAG;
+ } else if (type == AppsCustomizePagedView.ContentType.Widgets) {
+ return WIDGETS_TAB_TAG;
+ } else if (type == AppsCustomizePagedView.ContentType.Wallpapers) {
+ return WALLPAPERS_TAB_TAG;
+ }
+ return APPS_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();
+ }
+
+ /* LauncherTransitionable overrides */
+ @Override
+ public void onLauncherTransitionStart(android.animation.Animator animation) {
+ // TODO-APPS_CUSTOMIZE: see AllAppsTabbed.onLauncherTransitionStart();
+ }
+ @Override
+ public void onLauncherTransitionEnd(android.animation.Animator animation) {
+ // TODO-APPS_CUSTOMIZE: see AllAppsTabbed.onLauncherTransitionEnd();
+ }
+}
diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java
index 1464854..703b3a8 100644
--- a/src/com/android/launcher2/BubbleTextView.java
+++ b/src/com/android/launcher2/BubbleTextView.java
@@ -29,6 +29,7 @@
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
@@ -87,8 +88,6 @@
private void init() {
mBackground = getBackground();
- setFocusable(true);
- setBackgroundDrawable(null);
final Resources res = getContext().getResources();
int bubbleColor = res.getColor(R.color.bubble_dark_background);
@@ -330,4 +329,16 @@
}
return true;
}
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return FocusHelper.handleBubbleTextViewKeyEvent(this, keyCode, event)
+ || super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return FocusHelper.handleBubbleTextViewKeyEvent(this, keyCode, event)
+ || super.onKeyUp(keyCode, event);
+ }
}
diff --git a/src/com/android/launcher2/CachedTextView.java b/src/com/android/launcher2/CachedTextView.java
index 403d856..d0f6dd8 100644
--- a/src/com/android/launcher2/CachedTextView.java
+++ b/src/com/android/launcher2/CachedTextView.java
@@ -18,10 +18,11 @@
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.util.AttributeSet;
import android.widget.TextView;
@@ -163,6 +164,16 @@
if (mPrevAlpha != alpha) {
mPrevAlpha = alpha;
mCachePaint.setAlpha(alpha);
+
+ // We manually update the drawables alpha since the default TextView implementation may
+ // not do this if there is a background set (which we may due to the focus bg)
+ final Drawable[] dr = getCompoundDrawables();
+ for (int i = 0; i < dr.length; ++i) {
+ if (dr[i] != null) {
+ dr[i].mutate().setAlpha(alpha);
+ }
+ }
+
super.onSetAlpha(alpha);
}
return true;
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 1111c53..8efb6ce 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -16,7 +16,7 @@
package com.android.launcher2;
-import com.android.launcher.R;
+import java.util.Arrays;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -39,7 +39,6 @@
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.ContextMenu;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
@@ -48,7 +47,7 @@
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LayoutAnimationController;
-import java.util.Arrays;
+import com.android.launcher.R;
public class CellLayout extends ViewGroup {
static final String TAG = "CellLayout";
@@ -95,7 +94,7 @@
private float mGlowBackgroundScale;
private float mGlowBackgroundAlpha;
- private boolean mAcceptsDrops = false;
+ private boolean mAcceptsDrops = true;
// If we're actively dragging something over this screen, mIsDragOverlapping is true
private boolean mIsDragOverlapping = false;
private boolean mIsDragOccuring = false;
@@ -104,7 +103,7 @@
// These arrays are used to implement the drag visualization on x-large screens.
// They are used as circular arrays, indexed by mDragOutlineCurrent.
- private Point[] mDragOutlines = new Point[8];
+ private Point[] mDragOutlines = new Point[4];
private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
private InterruptibleInOutAnimator[] mDragOutlineAnims =
new InterruptibleInOutAnimator[mDragOutlines.length];
@@ -168,7 +167,7 @@
final Resources res = getResources();
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
mNormalBackground = res.getDrawable(R.drawable.homescreen_large_blue);
mActiveBackground = res.getDrawable(R.drawable.homescreen_large_green);
mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_large_green_strong);
@@ -264,17 +263,16 @@
setHoverAlpha(1.0f);
mChildren = new CellLayoutChildren(context);
- mChildren.setCellDimensions(
- mCellWidth, mCellHeight, mLeftPadding, mTopPadding, mWidthGap, mHeightGap);
+ mChildren.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
addView(mChildren);
}
private void invalidateBubbleTextView(BubbleTextView icon) {
final int padding = icon.getPressedOrFocusedBackgroundPadding();
- invalidate(icon.getLeft() - padding,
- icon.getTop() - padding,
- icon.getRight() + padding,
- icon.getBottom() + padding);
+ invalidate(icon.getLeft() + getLeftPadding() - padding,
+ icon.getTop() + getTopPadding() - padding,
+ icon.getRight() + getLeftPadding() + padding,
+ icon.getBottom() + getTopPadding() + padding);
}
void setPressedOrFocusedIcon(BubbleTextView icon) {
@@ -355,7 +353,7 @@
}
void animateDrop() {
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
Resources res = getResources();
float onDropScale = res.getInteger(R.integer.config_screenOnDropScalePercent) / 100.0f;
ObjectAnimator scaleUp = ObjectAnimator.ofFloat(this, "hoverScale", onDropScale);
@@ -393,7 +391,7 @@
// When we're small, we are either drawn normally or in the "accepts drops" state (during
// a drag). However, we also drag the mini hover background *over* one of those two
// backgrounds
- if (LauncherApplication.isScreenXLarge() && mBackgroundAlpha > 0.0f) {
+ if (LauncherApplication.isScreenLarge() && mBackgroundAlpha > 0.0f) {
Drawable bg;
boolean mini = getScaleX() < 0.5f;
@@ -488,8 +486,8 @@
final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
if (b != null) {
canvas.drawBitmap(b,
- mPressedOrFocusedIcon.getLeft() - padding,
- mPressedOrFocusedIcon.getTop() - padding,
+ mPressedOrFocusedIcon.getLeft() + getLeftPadding() - padding,
+ mPressedOrFocusedIcon.getTop() + getTopPadding() - padding,
null);
}
}
@@ -736,6 +734,22 @@
result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
}
+ /**
+ * Given a cell coordinate, return the point that represents the upper left corner of that cell
+ *
+ * @param cellX X coordinate of the cell
+ * @param cellY Y coordinate of the cell
+ *
+ * @param result Array of 2 ints to hold the x and y coordinate of the point
+ */
+ void cellToCenterPoint(int cellX, int cellY, int[] result) {
+ final int hStartPadding = getLeftPadding();
+ final int vStartPadding = getTopPadding();
+
+ result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + mCellWidth / 2;
+ result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + mCellHeight / 2;
+ }
+
int getCellWidth() {
return mCellWidth;
}
@@ -768,6 +782,18 @@
return mBottomPadding;
}
+ Rect getContentRect(Rect r) {
+ if (r == null) {
+ r = new Rect();
+ }
+ int left = getPaddingLeft();
+ int top = getPaddingTop();
+ int right = left + getWidth() - mLeftPadding - mRightPadding;
+ int bottom = top + getHeight() - mTopPadding - mBottomPadding;
+ r.set(left, top, right, bottom);
+ return r;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO: currently ignoring padding
@@ -827,7 +853,7 @@
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- child.layout(0, 0, r - l, b - t);
+ child.layout(mLeftPadding, mTopPadding, r - l - mRightPadding , b - t - mBottomPadding);
}
}
@@ -956,15 +982,23 @@
int top = topLeft[1];
if (v != null) {
- if (v.getParent() instanceof CellLayout) {
- LayoutParams lp = (LayoutParams) v.getLayoutParams();
- left += lp.leftMargin;
- top += lp.topMargin;
- }
+ // When drawing the drag outline, it did not account for margin offsets
+ // added by the view's parent.
+ MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
+ left += lp.leftMargin;
+ top += lp.topMargin;
- // Offsets due to the size difference between the View and the dragOutline
+ // Offsets due to the size difference between the View and the dragOutline.
+ // There is a size difference to account for the outer blur, which may lie
+ // outside the bounds of the view.
left += (v.getWidth() - dragOutline.getWidth()) / 2;
top += (v.getHeight() - dragOutline.getHeight()) / 2;
+ } else {
+ // Center the drag outline in the cell
+ left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
+ - dragOutline.getWidth()) / 2;
+ top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
+ - dragOutline.getHeight()) / 2;
}
final int oldIndex = mDragOutlineCurrent;
@@ -982,6 +1016,13 @@
}
}
+ public void clearDragOutlines() {
+ final int oldIndex = mDragOutlineCurrent;
+ mDragOutlineAnims[oldIndex].animateOut();
+ mDragCell[0] = -1;
+ mDragCell[1] = -1;
+ }
+
/**
* Find a vacant area that will fit the given bounds nearest the requested
* cell location. Uses Euclidean distance to score multiple vacant areas.
@@ -1008,16 +1049,23 @@
* @param pixelY The Y location at which you want to search for a vacant area.
* @param spanX Horizontal span of the object.
* @param spanY Vertical span of the object.
- * @param ignoreView Considers space occupied by this view as unoccupied
- * @param result Previously returned value to possibly recycle.
+ * @param ignoreOccupied If true, the result can be an occupied cell
+ * @param result Array in which to place the result, or null (in which case a new array will
+ * be allocated)
* @return The X, Y cell of a vacant area that can contain this object,
* nearest the requested location.
*/
- int[] findNearestVacantArea(
- int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
+ int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
+ boolean ignoreOccupied, int[] result) {
// mark space take by ignoreView as available (method checks if ignoreView is null)
markCellsAsUnoccupiedForView(ignoreView);
+ // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
+ // to the center of the item, but we are searching based on the top-left cell, so
+ // we translate the point over to correspond to the top-left.
+ pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
+ pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
+
// Keep track of best-scoring drop area
final int[] bestXY = result != null ? result : new int[2];
double bestDistance = Double.MAX_VALUE;
@@ -1029,18 +1077,20 @@
for (int y = 0; y < countY - (spanY - 1); y++) {
inner:
for (int x = 0; x < countX - (spanX - 1); x++) {
- for (int i = 0; i < spanX; i++) {
- for (int j = 0; j < spanY; j++) {
- if (occupied[x + i][y + j]) {
- // small optimization: we can skip to after the column we just found
- // an occupied cell
- x += i;
- continue inner;
+ if (ignoreOccupied) {
+ for (int i = 0; i < spanX; i++) {
+ for (int j = 0; j < spanY; j++) {
+ if (occupied[x + i][y + j]) {
+ // small optimization: we can skip to after the column we
+ // just found an occupied cell
+ x += i;
+ continue inner;
+ }
}
}
}
final int[] cellXY = mTmpCellXY;
- cellToPoint(x, y, cellXY);
+ cellToCenterPoint(x, y, cellXY);
double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
+ Math.pow(cellXY[1] - pixelY, 2));
@@ -1062,6 +1112,42 @@
}
}
+ /**
+ * Find a vacant area that will fit the given bounds nearest the requested
+ * cell location. Uses Euclidean distance to score multiple vacant areas.
+ *
+ * @param pixelX The X location at which you want to search for a vacant area.
+ * @param pixelY The Y location at which you want to search for a vacant area.
+ * @param spanX Horizontal span of the object.
+ * @param spanY Vertical span of the object.
+ * @param ignoreView Considers space occupied by this view as unoccupied
+ * @param result Previously returned value to possibly recycle.
+ * @return The X, Y cell of a vacant area that can contain this object,
+ * nearest the requested location.
+ */
+ int[] findNearestVacantArea(
+ int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
+ return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
+ }
+
+ /**
+ * Find a starting cell position that will fit the given bounds nearest the requested
+ * cell location. Uses Euclidean distance to score multiple vacant areas.
+ *
+ * @param pixelX The X location at which you want to search for a vacant area.
+ * @param pixelY The Y location at which you want to search for a vacant area.
+ * @param spanX Horizontal span of the object.
+ * @param spanY Vertical span of the object.
+ * @param ignoreView Considers space occupied by this view as unoccupied
+ * @param result Previously returned value to possibly recycle.
+ * @return The X, Y cell of a vacant area that can contain this object,
+ * nearest the requested location.
+ */
+ int[] findNearestArea(
+ int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+ return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
+ }
+
boolean existsEmptyCell() {
return findCellForSpan(null, 1, 1);
}
@@ -1457,6 +1543,14 @@
}
}
+ public boolean isOccupied(int x, int y) {
+ if (x < mCountX && y < mCountY) {
+ return mOccupied[x][y];
+ } else {
+ throw new RuntimeException("Position exceeds the bound of this CellLayout");
+ }
+ }
+
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new CellLayout.LayoutParams(getContext(), attrs);
@@ -1570,8 +1664,7 @@
this.cellVSpan = cellVSpan;
}
- public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
- int hStartPadding, int vStartPadding) {
+ public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
if (isLockedToGrid) {
final int myCellHSpan = cellHSpan;
final int myCellVSpan = cellVSpan;
@@ -1582,11 +1675,15 @@
leftMargin - rightMargin;
height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
topMargin - bottomMargin;
- x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
- y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+ x = myCellX * (cellWidth + widthGap) + leftMargin;
+ y = myCellY * (cellHeight + heightGap) + topMargin;
}
}
+ public String toString() {
+ return "(" + this.cellX + ", " + this.cellY + ")";
+ }
+
public void setWidth(int width) {
this.width = width;
}
@@ -1618,10 +1715,6 @@
public int getY() {
return y;
}
-
- public String toString() {
- return "(" + this.cellX + ", " + this.cellY + ")";
- }
}
// This class stores info for two purposes:
@@ -1630,7 +1723,7 @@
// 2. When long clicking on an empty cell in a CellLayout, we save information about the
// cellX and cellY coordinates and which page was clicked. We then set this as a tag on
// the CellLayout that was long clicked
- static final class CellInfo implements ContextMenu.ContextMenuInfo {
+ static final class CellInfo {
View cell;
int cellX = -1;
int cellY = -1;
diff --git a/src/com/android/launcher2/CellLayoutChildren.java b/src/com/android/launcher2/CellLayoutChildren.java
index 04996f3..f9adce0 100644
--- a/src/com/android/launcher2/CellLayoutChildren.java
+++ b/src/com/android/launcher2/CellLayoutChildren.java
@@ -16,12 +16,9 @@
package com.android.launcher2;
-import java.util.ArrayList;
-
import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Rect;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -34,33 +31,21 @@
private final WallpaperManager mWallpaperManager;
- private int mLeftPadding;
- private int mTopPadding;
-
private int mCellWidth;
private int mCellHeight;
private int mWidthGap;
private int mHeightGap;
- // Variables relating to resizing widgets
- private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
- new ArrayList<AppWidgetResizeFrame>();
- private AppWidgetResizeFrame mCurrentResizeFrame;
- private int mXDown, mYDown;
-
public CellLayoutChildren(Context context) {
super(context);
mWallpaperManager = WallpaperManager.getInstance(context);
setLayerType(LAYER_TYPE_HARDWARE, null);
}
- public void setCellDimensions(int cellWidth, int cellHeight,
- int leftPadding, int topPadding, int widthGap, int heightGap ) {
+ public void setCellDimensions(int cellWidth, int cellHeight, int widthGap, int heightGap ) {
mCellWidth = cellWidth;
mCellHeight = cellHeight;
- mLeftPadding = leftPadding;
- mTopPadding = topPadding;
mWidthGap = widthGap;
mHeightGap = heightGap;
}
@@ -72,7 +57,7 @@
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
- (lp.cellY <= y) && (y < lp.cellY + lp.cellHSpan)) {
+ (lp.cellY <= y) && (y < lp.cellY + lp.cellVSpan)) {
return child;
}
}
@@ -81,27 +66,29 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int cellWidth = mCellWidth;
- final int cellHeight = mCellHeight;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
- lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap,
- mLeftPadding, mTopPadding);
-
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
- int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
- MeasureSpec.EXACTLY);
-
- child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+ measureChild(child);
}
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthSpecSize, heightSpecSize);
}
+ public void measureChild(View child) {
+ final int cellWidth = mCellWidth;
+ final int cellHeight = mCellHeight;
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
+
+ lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap);
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
+ int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
+ MeasureSpec.EXACTLY);
+
+ child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+ }
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
@@ -176,95 +163,4 @@
protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
super.setChildrenDrawnWithCacheEnabled(enabled);
}
-
- public void clearAllResizeFrames() {
- for (AppWidgetResizeFrame frame: mResizeFrames) {
- removeView(frame);
- }
- mResizeFrames.clear();
- }
-
- public boolean hasResizeFrames() {
- return mResizeFrames.size() > 0;
- }
-
- public boolean isWidgetBeingResized() {
- return mCurrentResizeFrame != null;
- }
-
- private boolean handleTouchDown(MotionEvent ev) {
- Rect hitRect = new Rect();
-
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
- for (AppWidgetResizeFrame child: mResizeFrames) {
- child.getHitRect(hitRect);
- if (hitRect.contains(x, y)) {
- if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
- mCurrentResizeFrame = child;
- mXDown = x;
- mYDown = y;
- requestDisallowInterceptTouchEvent(true);
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (handleTouchDown(ev)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- boolean handled = false;
- int action = ev.getAction();
-
- int x = (int) ev.getX();
- int y = (int) ev.getY();
-
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (handleTouchDown(ev)) {
- return true;
- }
- }
- }
-
- if (mCurrentResizeFrame != null) {
- handled = true;
- switch (action) {
- case MotionEvent.ACTION_MOVE:
- mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown);
- mCurrentResizeFrame = null;
- }
- }
- return handled;
- }
-
- public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
- CellLayout cellLayout) {
- AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
- itemInfo, widget, cellLayout);
-
- CellLayout.LayoutParams lp = new CellLayout.LayoutParams(-1, -1, -1, -1);
- lp.isLockedToGrid = false;
-
- addView(resizeFrame, lp);
- mResizeFrames.add(resizeFrame);
-
- resizeFrame.snapToWidget(false);
- }
}
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 92b73a0..e5bc8b8 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -301,13 +301,8 @@
}
});
- Comparator<ResolveInfo> resolveInfoComparator = new Comparator<ResolveInfo>() {
- @Override
- public int compare(ResolveInfo object1, ResolveInfo object2) {
- return object1.loadLabel(mPackageManager).toString().compareTo(
- object2.loadLabel(mPackageManager).toString());
- }
- };
+ LauncherModel.ShortcutNameComparator resolveInfoComparator =
+ new LauncherModel.ShortcutNameComparator(mPackageManager);
// get the list of shortcuts
Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
@@ -488,8 +483,6 @@
@Override
public void onClick(final View v) {
- // Return early if this is not initiated from a touch
- if (!v.isInTouchMode()) return;
// Return early if we are still animating the pages
if (mNextPage != INVALID_PAGE) return;
@@ -936,12 +929,13 @@
final int[] cellSpans = CellLayout.rectToCell(getResources(), info.minWidth,
info.minHeight, null);
final FastBitmapDrawable icon = getWidgetPreview(info);
+ final boolean createHolographicOutlines = (numPages > 1);
PagedViewWidget l = (PagedViewWidget) mInflater.inflate(
R.layout.customize_paged_view_widget, layout, false);
l.applyFromAppWidgetProviderInfo(info, icon, mMaxWidgetWidth, cellSpans,
- mPageViewIconCache, (numPages > 1));
+ mPageViewIconCache, createHolographicOutlines);
l.setTag(createItemInfo);
l.setOnClickListener(this);
l.setOnTouchListener(this);
@@ -982,11 +976,12 @@
for (int i = startIndex; i < endIndex; ++i) {
final ResolveInfo info = mWallpaperList.get(i);
final FastBitmapDrawable icon = getWallpaperPreview(info);
+ final boolean createHolographicOutlines = (numPages > 1);
PagedViewWidget l = (PagedViewWidget) mInflater.inflate(
R.layout.customize_paged_view_wallpaper, layout, false);
l.applyFromWallpaperInfo(info, mPackageManager, icon, mMaxWidgetWidth,
- mPageViewIconCache, (numPages > 1));
+ mPageViewIconCache, createHolographicOutlines);
l.setTag(info);
l.setOnClickListener(this);
@@ -1019,12 +1014,13 @@
for (int i = startIndex; i < endIndex; ++i) {
ResolveInfo info = list.get(i);
PendingAddItemInfo createItemInfo = new PendingAddItemInfo();
+ final boolean createHolographicOutlines = (numPages > 1);
PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
R.layout.customize_paged_view_item, layout, false);
icon.applyFromResolveInfo(info, mPackageManager, mPageViewIconCache,
((LauncherApplication) mLauncher.getApplication()).getIconCache(),
- (numPages > 1));
+ createHolographicOutlines);
switch (mCustomizationType) {
case WallpaperCustomization:
icon.setOnClickListener(this);
@@ -1046,7 +1042,8 @@
final int x = index % mCellCountX;
final int y = index / mCellCountX;
setupPage(layout);
- layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
+ layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1),
+ createHolographicOutlines);
}
}
@@ -1078,9 +1075,11 @@
layout.removeAllViewsOnPage();
for (int i = startIndex; i < endIndex; ++i) {
final ApplicationInfo info = mApps.get(i);
+ final boolean createHolographicOutlines = (numPages > 1);
PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
R.layout.all_apps_paged_view_application, layout, false);
- icon.applyFromApplicationInfo(info, mPageViewIconCache, true, (numPages > 1));
+ icon.applyFromApplicationInfo(
+ info, mPageViewIconCache, true, createHolographicOutlines);
icon.setOnClickListener(this);
icon.setOnTouchListener(this);
icon.setOnLongClickListener(this);
@@ -1089,7 +1088,8 @@
final int x = index % mCellCountX;
final int y = index / mCellCountX;
setupPage(layout);
- layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
+ layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1),
+ createHolographicOutlines);
}
}
@@ -1135,8 +1135,10 @@
}
// Set a min page width for PagedView layout if we have more than a single page
- if (enforceMinimumPagedWidths) {
- setMinimumWidthOverride((childCount > 1) ? mMinPageWidth : 0);
+ if (enforceMinimumPagedWidths && childCount > 1) {
+ setMinimumWidthOverride(mMinPageWidth);
+ } else {
+ resetMinimumWidthOverride();
}
// Bound the current page index
diff --git a/src/com/android/launcher2/CustomizeTrayTabHost.java b/src/com/android/launcher2/CustomizeTrayTabHost.java
index 3e04025..2c47895 100644
--- a/src/com/android/launcher2/CustomizeTrayTabHost.java
+++ b/src/com/android/launcher2/CustomizeTrayTabHost.java
@@ -16,8 +16,7 @@
package com.android.launcher2;
-import com.android.launcher.R;
-import com.android.launcher2.CustomizePagedView.CustomizationType;
+import java.util.Random;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,10 +27,14 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
+import com.android.launcher.R;
+import com.android.launcher2.CustomizePagedView.CustomizationType;
+
public class CustomizeTrayTabHost extends TabHost implements LauncherTransitionable {
// tags for the customization tabs
private static final String WIDGETS_TAG = "widgets";
@@ -69,7 +72,8 @@
tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
tabView.setText(mContext.getString(R.string.widgets_tab_label));
- addTab(newTabSpec(WIDGETS_TAG).setIndicator(tabView).setContent(contentFactory));
+ addTab(newTabSpec(WIDGETS_TAG)
+ .setIndicator(tabView).setContent(contentFactory));
tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
tabView.setText(mContext.getString(R.string.applications_tab_label));
addTab(newTabSpec(APPLICATIONS_TAG)
@@ -82,6 +86,7 @@
tabView.setText(mContext.getString(R.string.shortcuts_tab_label));
addTab(newTabSpec(SHORTCUTS_TAG)
.setIndicator(tabView).setContent(contentFactory));
+
setOnTabChangedListener(new OnTabChangeListener() {
public void onTabChanged(String tabId) {
final CustomizePagedView.CustomizationType newType =
@@ -89,7 +94,7 @@
if (newType != customizePagedView.getCustomizationFilter()) {
// animate the changing of the tab content by fading pages in and out
final Resources res = getResources();
- final int duration = res.getInteger(R.integer.config_tabTransitionTime);
+ final int duration = res.getInteger(R.integer.config_tabTransitionDuration);
final float alpha = customizePagedView.getAlpha();
ValueAnimator alphaAnim = ObjectAnimator.ofFloat(customizePagedView,
"alpha", alpha, 0.0f);
@@ -149,6 +154,14 @@
super.onLayout(changed, l, t, r, b);
}
+ @Override
+ public int getDescendantFocusability() {
+ if (getVisibility() != View.VISIBLE) {
+ return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+ }
+ return super.getDescendantFocusability();
+ }
+
CustomizationType getCustomizeFilterForTabTag(String tag) {
if (tag.equals(WIDGETS_TAG)) {
return CustomizationType.WidgetCustomization;
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index 98d2b83..fdd4125 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -16,8 +16,10 @@
package com.android.launcher2;
-import com.android.launcher.R;
-
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -29,10 +31,8 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.TranslateAnimation;
+
+import com.android.launcher.R;
public class DeleteZone extends IconDropTarget {
private static final int ORIENTATION_HORIZONTAL = 1;
@@ -42,10 +42,8 @@
private static final int XLARGE_ANIMATION_DURATION = 200;
private static final int LEFT_DRAWABLE = 0;
- private AnimationSet mInAnimation;
- private AnimationSet mOutAnimation;
- private Animation mHandleInAnimation;
- private Animation mHandleOutAnimation;
+ private AnimatorSet mInAnimation;
+ private AnimatorSet mOutAnimation;
private int mOrientation;
private DragController mDragController;
@@ -70,7 +68,7 @@
mOrientation = a.getInt(R.styleable.DeleteZone_direction, ORIENTATION_HORIZONTAL);
a.recycle();
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
int tb = getResources().getDimensionPixelSize(
R.dimen.delete_zone_vertical_drag_padding);
int lr = getResources().getDimensionPixelSize(
@@ -83,7 +81,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mTransition = (TransitionDrawable) getCompoundDrawables()[LEFT_DRAWABLE];
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
mTransition.setCrossFadeEnabled(false);
}
@@ -104,7 +102,7 @@
final ItemInfo item = (ItemInfo) dragInfo;
// On x-large screens, you can uninstall an app by dragging from all apps
- if (item instanceof ApplicationInfo && LauncherApplication.isScreenXLarge()) {
+ if (item instanceof ApplicationInfo && LauncherApplication.isScreenLarge()) {
mLauncher.startApplicationUninstallActivity((ApplicationInfo) item);
}
@@ -114,18 +112,18 @@
if (item instanceof LauncherAppWidgetInfo) {
mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
}
- } else if (source instanceof UserFolder) {
- final UserFolder userFolder = (UserFolder) source;
- final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo();
+ } else if (source instanceof Folder) {
+ final Folder folder = (Folder) source;
+ final FolderInfo folderInfo = (FolderInfo) folder.getInfo();
// Item must be a ShortcutInfo otherwise it couldn't have been in the folder
// in the first place.
- userFolderInfo.remove((ShortcutInfo)item);
+ folderInfo.remove((ShortcutInfo)item);
}
- if (item instanceof UserFolderInfo) {
- final UserFolderInfo userFolderInfo = (UserFolderInfo)item;
- LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo);
- mLauncher.removeFolder(userFolderInfo);
+ if (item instanceof FolderInfo) {
+ final FolderInfo folderInfo = (FolderInfo)item;
+ LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo);
+ mLauncher.removeFolder(folderInfo);
} else if (item instanceof LauncherAppWidgetInfo) {
final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
@@ -168,7 +166,7 @@
getHitRect(mRegion);
mRegionF.set(mRegion);
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
// This region will be a "dead zone" for scrolling; make it extend to the edge of
// the screen so users don't accidentally trigger a scroll while deleting items
mRegionF.top = mLauncher.getWorkspace().getTop();
@@ -181,10 +179,10 @@
mTransition.resetTransition();
createAnimations();
- startAnimation(mInAnimation);
+ mInAnimation.start();
if (mOverlappingViews != null) {
for (View view : mOverlappingViews) {
- view.startAnimation(mHandleOutAnimation);
+ createOutAlphaAnim(view).start();
}
}
setVisibility(VISIBLE);
@@ -196,68 +194,72 @@
mActive = false;
mDragController.setDeleteRegion(null);
- if (mOutAnimation != null) startAnimation(mOutAnimation);
- if (mHandleInAnimation != null && mOverlappingViews != null) {
+ mOutAnimation.start();
+ if (mOverlappingViews != null) {
for (View view : mOverlappingViews) {
- view.startAnimation(mHandleInAnimation);
+ createInAlphaAnim(view).start();
}
}
- setVisibility(GONE);
}
}
+ private Animator createAlphaAnim(View v, float start, float end) {
+ Animator anim = ObjectAnimator.ofFloat(v, "alpha", start, end);
+ anim.setDuration(getAnimationDuration());
+ return anim;
+ }
+ private Animator createInAlphaAnim(View v) {
+ return createAlphaAnim(v, 0f, 1f);
+ }
+ private Animator createOutAlphaAnim(View v) {
+ return createAlphaAnim(v, 1f, 0f);
+ }
+
private void createAnimations() {
int duration = getAnimationDuration();
- if (mHandleInAnimation == null) {
- mHandleInAnimation = new AlphaAnimation(0.0f, 1.0f);
- mHandleInAnimation.setDuration(duration);
- }
+ Animator inAlphaAnim = createInAlphaAnim(this);
if (mInAnimation == null) {
- mInAnimation = new FastAnimationSet();
- if (!LauncherApplication.isScreenXLarge()) {
- final AnimationSet animationSet = mInAnimation;
- animationSet.setInterpolator(new AccelerateInterpolator());
- animationSet.addAnimation(new AlphaAnimation(0.0f, 1.0f));
+ mInAnimation = new AnimatorSet();
+ mInAnimation.setInterpolator(new AccelerateInterpolator());
+ mInAnimation.setDuration(duration);
+ if (!LauncherApplication.isScreenLarge()) {
+ Animator translateAnim;
if (mOrientation == ORIENTATION_HORIZONTAL) {
- animationSet.addAnimation(new TranslateAnimation(Animation.ABSOLUTE, 0.0f,
- Animation.ABSOLUTE, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f,
- Animation.RELATIVE_TO_SELF, 0.0f));
+ translateAnim = ObjectAnimator.ofFloat(this, "translationY",
+ getMeasuredWidth(), 0f);
} else {
- animationSet.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF,
- 1.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.ABSOLUTE, 0.0f,
- Animation.ABSOLUTE, 0.0f));
+ translateAnim = ObjectAnimator.ofFloat(this, "translationX",
+ getMeasuredHeight(), 0f);
}
- animationSet.setDuration(duration);
+ mInAnimation.playTogether(translateAnim, inAlphaAnim);
} else {
- mInAnimation.addAnimation(mHandleInAnimation);
+ mInAnimation.play(inAlphaAnim);
}
}
- if (mHandleOutAnimation == null) {
- mHandleOutAnimation = new AlphaAnimation(1.0f, 0.0f);
- mHandleOutAnimation.setFillAfter(true);
- mHandleOutAnimation.setDuration(duration);
- }
-
+ Animator outAlphaAnim = createOutAlphaAnim(this);
if (mOutAnimation == null) {
- mOutAnimation = new FastAnimationSet();
- if (!LauncherApplication.isScreenXLarge()) {
- final AnimationSet animationSet = mOutAnimation;
- animationSet.setInterpolator(new AccelerateInterpolator());
- animationSet.addAnimation(new AlphaAnimation(1.0f, 0.0f));
+ mOutAnimation = new AnimatorSet();
+ mOutAnimation.setInterpolator(new AccelerateInterpolator());
+ mOutAnimation.setDuration(duration);
+ if (!LauncherApplication.isScreenLarge()) {
+ Animator translateAnim;
if (mOrientation == ORIENTATION_HORIZONTAL) {
- animationSet.addAnimation(new FastTranslateAnimation(Animation.ABSOLUTE, 0.0f,
- Animation.ABSOLUTE, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
- Animation.RELATIVE_TO_SELF, 1.0f));
+ translateAnim = ObjectAnimator.ofFloat(this, "translationY", 0f,
+ getMeasuredWidth());
} else {
- animationSet.addAnimation(new FastTranslateAnimation(Animation.RELATIVE_TO_SELF,
- 0.0f, Animation.RELATIVE_TO_SELF, 1.0f, Animation.ABSOLUTE, 0.0f,
- Animation.ABSOLUTE, 0.0f));
+ translateAnim = ObjectAnimator.ofFloat(this, "translationX", 0f,
+ getMeasuredHeight());
}
- animationSet.setDuration(duration);
+ mOutAnimation.playTogether(translateAnim, outAlphaAnim);
} else {
- mOutAnimation.addAnimation(mHandleOutAnimation);
+ mOutAnimation.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ setVisibility(GONE);
+ }
+ });
+ mOutAnimation.play(outAlphaAnim);
}
}
}
@@ -267,46 +269,12 @@
}
private int getTransitionAnimationDuration() {
- return LauncherApplication.isScreenXLarge() ?
+ return LauncherApplication.isScreenLarge() ?
XLARGE_TRANSITION_DURATION : TRANSITION_DURATION;
}
private int getAnimationDuration() {
- return LauncherApplication.isScreenXLarge() ?
+ return LauncherApplication.isScreenLarge() ?
XLARGE_ANIMATION_DURATION : ANIMATION_DURATION;
}
-
- private static class FastTranslateAnimation extends TranslateAnimation {
- public FastTranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
- int fromYType, float fromYValue, int toYType, float toYValue) {
- super(fromXType, fromXValue, toXType, toXValue,
- fromYType, fromYValue, toYType, toYValue);
- }
-
- @Override
- public boolean willChangeTransformationMatrix() {
- return true;
- }
-
- @Override
- public boolean willChangeBounds() {
- return false;
- }
- }
-
- private static class FastAnimationSet extends AnimationSet {
- FastAnimationSet() {
- super(false);
- }
-
- @Override
- public boolean willChangeTransformationMatrix() {
- return true;
- }
-
- @Override
- public boolean willChangeBounds() {
- return false;
- }
- }
}
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index cb4509b..5ca1e1c 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -73,10 +73,10 @@
private boolean mDragging;
/** X coordinate of the down event. */
- private float mMotionDownX;
+ private int mMotionDownX;
/** Y coordinate of the down event. */
- private float mMotionDownY;
+ private int mMotionDownY;
/** Info about the screen for clamping. */
private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
@@ -85,10 +85,10 @@
private View mOriginator;
/** X offset from the upper-left corner of the cell to where we touched. */
- private float mTouchOffsetX;
+ private int mTouchOffsetX;
/** Y offset from the upper-left corner of the cell to where we touched. */
- private float mTouchOffsetY;
+ private int mTouchOffsetY;
/** the area at the edge of the screen that makes the workspace go left
* or right while you're dragging.
@@ -289,13 +289,14 @@
listener.onDragStart(source, dragInfo, dragAction);
}
- int registrationX = ((int)mMotionDownX) - screenX;
- int registrationY = ((int)mMotionDownY) - screenY;
+ final int registrationX = ((int)mMotionDownX) - screenX;
+ final int registrationY = ((int)mMotionDownY) - screenY;
final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
- mTouchOffsetX = mMotionDownX - screenX - dragRegionLeft;
- mTouchOffsetY = mMotionDownY - screenY - dragRegionTop;
+
+ mTouchOffsetX = mMotionDownX - (screenX + dragRegionLeft);
+ mTouchOffsetY = mMotionDownY - (screenY + dragRegionTop);
mDragging = true;
mDragSource = source;
@@ -314,8 +315,7 @@
});
if (dragRegion != null) {
- dragView.setDragRegion(dragRegionLeft, dragRegion.top,
- dragRegion.right - dragRegionLeft, dragRegion.bottom - dragRegionTop);
+ dragView.setDragRegion(new Rect(dragRegion));
}
dragView.show(mWindowToken, (int)mMotionDownX, (int)mMotionDownY);
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index eb53945..c2b710e 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -16,10 +16,11 @@
package com.android.launcher2;
-import com.android.launcher.R;
+import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -27,6 +28,8 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.launcher.R;
+
/**
* A ViewGroup that coordinates dragging across its descendants
*/
@@ -34,6 +37,12 @@
private DragController mDragController;
private int[] mTmpXY = new int[2];
+ // Variables relating to resizing widgets
+ private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
+ new ArrayList<AppWidgetResizeFrame>();
+ private AppWidgetResizeFrame mCurrentResizeFrame;
+ private int mXDown, mYDown;
+
/**
* Used to create a new DragLayer from XML.
*
@@ -56,31 +65,66 @@
return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
}
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // If the current CellLayoutChildren has a resize frame, we need to detect if any touch
- // event has occurred which doesn't result in resizing a widget. In this case, we
- // dismiss any visible resize frames.
- final Workspace w = (Workspace) findViewById(R.id.workspace);
- if (w != null) {
- final CellLayout currentPage = (CellLayout) w.getChildAt(w.getCurrentPage());
- final CellLayoutChildren childrenLayout = currentPage.getChildrenLayout();
+ private boolean handleTouchDown(MotionEvent ev) {
+ Rect hitRect = new Rect();
+ int x = (int) ev.getX();
+ int y = (int) ev.getY();
- if (childrenLayout.hasResizeFrames() && !childrenLayout.isWidgetBeingResized()) {
- post(new Runnable() {
- public void run() {
- if (!childrenLayout.isWidgetBeingResized()) {
- childrenLayout.clearAllResizeFrames();
- }
- }
- });
+ for (AppWidgetResizeFrame child: mResizeFrames) {
+ child.getHitRect(hitRect);
+ if (hitRect.contains(x, y)) {
+ if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
+ mCurrentResizeFrame = child;
+ mXDown = x;
+ mYDown = y;
+ requestDisallowInterceptTouchEvent(true);
+ return true;
+ }
}
}
+ return false;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ if (handleTouchDown(ev)) {
+ return true;
+ }
+ }
+ clearAllResizeFrames();
return mDragController.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
+ boolean handled = false;
+ int action = ev.getAction();
+
+ int x = (int) ev.getX();
+ int y = (int) ev.getY();
+
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ if (handleTouchDown(ev)) {
+ return true;
+ }
+ }
+ }
+
+ if (mCurrentResizeFrame != null) {
+ handled = true;
+ switch (action) {
+ case MotionEvent.ACTION_MOVE:
+ mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown);
+ mCurrentResizeFrame = null;
+ }
+ }
+ if (handled) return true;
return mDragController.onTouchEvent(ev);
}
@@ -103,4 +147,94 @@
v.getLocationOnScreen(mTmpXY);
return createDragView(mDragController.getViewBitmap(v), mTmpXY[0], mTmpXY[1]);
}
+
+ public static class LayoutParams extends FrameLayout.LayoutParams {
+ public int x, y;
+ public boolean customPosition = false;
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public void setY(int y) {
+ this.y = y;
+ }
+
+ public int getY() {
+ return y;
+ }
+ }
+
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
+ if (flp instanceof LayoutParams) {
+ final LayoutParams lp = (LayoutParams) flp;
+ if (lp.customPosition) {
+ child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
+ }
+ }
+ }
+ }
+
+ public void clearAllResizeFrames() {
+ if (mResizeFrames.size() > 0) {
+ for (AppWidgetResizeFrame frame: mResizeFrames) {
+ removeView(frame);
+ }
+ mResizeFrames.clear();
+ }
+ }
+
+ public boolean hasResizeFrames() {
+ return mResizeFrames.size() > 0;
+ }
+
+ public boolean isWidgetBeingResized() {
+ return mCurrentResizeFrame != null;
+ }
+
+ public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
+ CellLayout cellLayout) {
+ AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
+ itemInfo, widget, cellLayout, this);
+
+ LayoutParams lp = new LayoutParams(-1, -1);
+ lp.customPosition = true;
+
+ addView(resizeFrame, lp);
+ mResizeFrames.add(resizeFrame);
+
+ resizeFrame.snapToWidget(false);
+ }
}
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
index 4dbdaf7..649120d 100644
--- a/src/com/android/launcher2/DragSource.java
+++ b/src/com/android/launcher2/DragSource.java
@@ -23,8 +23,6 @@
*
*/
public interface DragSource {
- void setDragController(DragController dragger);
-
/**
* Callback from the DragController when it begins drawing the drag view.
* This allows the DragSource to dim or hide the original view.
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index 45620b9..b02e22b 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -26,6 +26,7 @@
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.os.IBinder;
import android.view.Gravity;
import android.view.View;
@@ -42,10 +43,7 @@
private int mRegistrationX;
private int mRegistrationY;
- private int mDragRegionLeft = 0;
- private int mDragRegionTop = 0;
- private int mDragRegionWidth;
- private int mDragRegionHeight;
+ private Rect mDragRegion = null;
ValueAnimator mAnim;
private float mOffsetX = 0.0f;
@@ -87,8 +85,8 @@
scale.setScale(scaleFactor, scaleFactor);
}
- final int offsetX = res.getInteger(R.integer.config_dragViewOffsetX);
- final int offsetY = res.getInteger(R.integer.config_dragViewOffsetY);
+ final int offsetX = res.getDimensionPixelSize(R.dimen.dragViewOffsetX);
+ final int offsetY = res.getDimensionPixelSize(R.dimen.dragViewOffsetY);
// Animate the view into the correct position
mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
@@ -117,7 +115,7 @@
});
mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height, scale, true);
- setDragRegion(0, 0, width, height);
+ setDragRegion(new Rect(0, 0, width, height));
// The point in our scaled bitmap that the touch events are located
mRegistrationX = registrationX;
@@ -132,31 +130,32 @@
return mOffsetY;
}
- public void setDragRegion(int left, int top, int width, int height) {
- mDragRegionLeft = left;
- mDragRegionTop = top;
- mDragRegionWidth = width;
- mDragRegionHeight = height;
- }
-
public void setOnDrawRunnable(Runnable r) {
mOnDrawRunnable = r;
}
public int getDragRegionLeft() {
- return mDragRegionLeft;
+ return mDragRegion.left;
}
public int getDragRegionTop() {
- return mDragRegionTop;
+ return mDragRegion.top;
}
public int getDragRegionWidth() {
- return mDragRegionWidth;
+ return mDragRegion.width();
}
public int getDragRegionHeight() {
- return mDragRegionHeight;
+ return mDragRegion.height();
+ }
+
+ public void setDragRegion(Rect r) {
+ mDragRegion = r;
+ }
+
+ public Rect getDragRegion() {
+ return mDragRegion;
}
@Override
diff --git a/src/com/android/launcher2/FocusHelper.java b/src/com/android/launcher2/FocusHelper.java
new file mode 100644
index 0000000..861a70b
--- /dev/null
+++ b/src/com/android/launcher2/FocusHelper.java
@@ -0,0 +1,1056 @@
+/*
+ * 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.launcher2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import android.content.res.Configuration;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+
+import com.android.launcher.R;
+
+/**
+ * A keyboard listener we set on all the button bar buttons.
+ */
+class ButtonBarKeyEventListener implements View.OnKeyListener {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ return FocusHelper.handleButtonBarButtonKeyEvent(v, keyCode, event);
+ }
+}
+
+/**
+ * A keyboard listener we set on the indicator buttons.
+ */
+class IndicatorKeyEventListener implements View.OnKeyListener {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ return FocusHelper.handleIndicatorButtonKeyEvent(v, keyCode, event);
+ }
+}
+
+/**
+ * A keyboard listener we set on all the dock buttons.
+ */
+class DockKeyEventListener implements View.OnKeyListener {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ final Configuration configuration = v.getResources().getConfiguration();
+ return FocusHelper.handleDockButtonKeyEvent(v, keyCode, event, configuration.orientation);
+ }
+}
+
+/**
+ * A keyboard listener we set on the last tab button in AllApps to jump to then
+ * market icon and vice versa.
+ */
+class AllAppsTabKeyEventListener implements View.OnKeyListener {
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ return FocusHelper.handleAllAppsTabKeyEvent(v, keyCode, event);
+ }
+}
+
+public class FocusHelper {
+ /**
+ * Private helper to get the parent TabHost in the view hiearchy.
+ */
+ private static TabHost findTabHostParent(View v) {
+ ViewParent p = v.getParent();
+ while (p != null && !(p instanceof TabHost)) {
+ p = p.getParent();
+ }
+ return (TabHost) p;
+ }
+
+ /**
+ * Handles key events in a AllApps tab between the last tab view and the shop button.
+ */
+ static boolean handleAllAppsTabKeyEvent(View v, int keyCode, KeyEvent e) {
+ final TabHost tabHost = findTabHostParent(v);
+ final ViewGroup contents = (ViewGroup)
+ tabHost.findViewById(com.android.internal.R.id.tabcontent);
+ final View shop = tabHost.findViewById(R.id.market_button);
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ // Select the shop button if we aren't on it
+ if (v != shop) {
+ shop.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (handleKeyEvent) {
+ // Select the content view (down is handled by the tab key handler otherwise)
+ if (v == shop) {
+ contents.requestFocus();
+ wasHandled = true;
+ }
+ }
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+
+ /**
+ * Private helper to determine whether a view is visible.
+ */
+ private static boolean isVisible(View v) {
+ return v.getVisibility() == View.VISIBLE;
+ }
+
+ /**
+ * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
+ * To be deprecated.
+ */
+ static boolean handlePagedViewWidgetKeyEvent(PagedViewWidget w, int keyCode, KeyEvent e) {
+ if (!LauncherApplication.isScreenLarge()) return false;
+
+ final PagedViewExtendedLayout parent = (PagedViewExtendedLayout) w.getParent();
+ final ViewGroup container = (ViewGroup) parent.getParent();
+ final TabHost tabHost = findTabHostParent(container);
+ final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
+ final int widgetIndex = parent.indexOfChild(w);
+ final int widgetCount = parent.getChildCount();
+ final int pageIndex = container.indexOfChild(parent);
+ final int pageCount = container.getChildCount();
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ PagedViewExtendedLayout newParent = null;
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (handleKeyEvent) {
+ // Select the previous widget or the last widget on the previous page
+ if (widgetIndex > 0) {
+ parent.getChildAt(widgetIndex - 1).requestFocus();
+ } else {
+ if (pageIndex > 0) {
+ newParent = (PagedViewExtendedLayout)
+ container.getChildAt(pageIndex - 1);
+ newParent.getChildAt(newParent.getChildCount() - 1).requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ // Select the next widget or the first widget on the next page
+ if (widgetIndex < (widgetCount - 1)) {
+ parent.getChildAt(widgetIndex + 1).requestFocus();
+ } else {
+ if (pageIndex < (pageCount - 1)) {
+ newParent = (PagedViewExtendedLayout)
+ container.getChildAt(pageIndex + 1);
+ newParent.getChildAt(0).requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (handleKeyEvent) {
+ // Select widgets tab on the tab bar
+ tabs.requestFocus();
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (handleKeyEvent) {
+ // TODO: Should focus the global search bar
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ if (handleKeyEvent) {
+ // Simulate a click on the widget
+ View.OnClickListener clickListener = (View.OnClickListener) container;
+ clickListener.onClick(w);
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_PAGE_UP:
+ if (handleKeyEvent) {
+ // Select the first item on the previous page, or the first item on this page
+ // if there is no previous page
+ if (pageIndex > 0) {
+ newParent = (PagedViewExtendedLayout) container.getChildAt(pageIndex - 1);
+ newParent.getChildAt(0).requestFocus();
+ } else {
+ parent.getChildAt(0).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_PAGE_DOWN:
+ if (handleKeyEvent) {
+ // Select the first item on the next page, or the last item on this page
+ // if there is no next page
+ if (pageIndex < (pageCount - 1)) {
+ newParent = (PagedViewExtendedLayout) container.getChildAt(pageIndex + 1);
+ newParent.getChildAt(0).requestFocus();
+ } else {
+ parent.getChildAt(widgetCount - 1).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_MOVE_HOME:
+ if (handleKeyEvent) {
+ // Select the first item on this page
+ parent.getChildAt(0).requestFocus();
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_MOVE_END:
+ if (handleKeyEvent) {
+ // Select the last item on this page
+ parent.getChildAt(widgetCount - 1).requestFocus();
+ }
+ wasHandled = true;
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+
+ /**
+ * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
+ */
+ static boolean handlePagedViewGridLayoutWidgetKeyEvent(PagedViewWidget w, int keyCode,
+ KeyEvent e) {
+
+ final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent();
+ final ViewGroup container = (ViewGroup) parent.getParent();
+ final TabHost tabHost = findTabHostParent(container);
+ final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
+ final int widgetIndex = parent.indexOfChild(w);
+ final int widgetCount = parent.getChildCount();
+ final int pageIndex = container.indexOfChild(parent);
+ final int pageCount = container.getChildCount();
+ final int cellCountX = parent.getCellCountX();
+ final int cellCountY = parent.getCellCountY();
+ final int x = widgetIndex % cellCountX;
+ final int y = widgetIndex / cellCountX;
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ PagedViewGridLayout newParent = null;
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (handleKeyEvent) {
+ // Select the previous widget or the last widget on the previous page
+ if (widgetIndex > 0) {
+ parent.getChildAt(widgetIndex - 1).requestFocus();
+ } else {
+ if (pageIndex > 0) {
+ newParent = (PagedViewGridLayout)
+ container.getChildAt(pageIndex - 1);
+ newParent.getChildAt(newParent.getChildCount() - 1).requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ // Select the next widget or the first widget on the next page
+ if (widgetIndex < (widgetCount - 1)) {
+ parent.getChildAt(widgetIndex + 1).requestFocus();
+ } else {
+ if (pageIndex < (pageCount - 1)) {
+ newParent = (PagedViewGridLayout)
+ container.getChildAt(pageIndex + 1);
+ newParent.getChildAt(0).requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (handleKeyEvent) {
+ // Select the closest icon in the previous row, otherwise select the tab bar
+ if (y > 0) {
+ int newWidgetIndex = ((y - 1) * cellCountX) + x;
+ parent.getChildAt(newWidgetIndex).requestFocus();
+ } else {
+ tabs.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (handleKeyEvent) {
+ // Select the closest icon in the previous row, otherwise do nothing
+ if (y < (cellCountY - 1)) {
+ int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
+ parent.getChildAt(newWidgetIndex).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ if (handleKeyEvent) {
+ // Simulate a click on the widget
+ View.OnClickListener clickListener = (View.OnClickListener) container;
+ clickListener.onClick(w);
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_PAGE_UP:
+ if (handleKeyEvent) {
+ // Select the first item on the previous page, or the first item on this page
+ // if there is no previous page
+ if (pageIndex > 0) {
+ newParent = (PagedViewGridLayout) container.getChildAt(pageIndex - 1);
+ newParent.getChildAt(0).requestFocus();
+ } else {
+ parent.getChildAt(0).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_PAGE_DOWN:
+ if (handleKeyEvent) {
+ // Select the first item on the next page, or the last item on this page
+ // if there is no next page
+ if (pageIndex < (pageCount - 1)) {
+ newParent = (PagedViewGridLayout) container.getChildAt(pageIndex + 1);
+ newParent.getChildAt(0).requestFocus();
+ } else {
+ parent.getChildAt(widgetCount - 1).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_MOVE_HOME:
+ if (handleKeyEvent) {
+ // Select the first item on this page
+ parent.getChildAt(0).requestFocus();
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_MOVE_END:
+ if (handleKeyEvent) {
+ // Select the last item on this page
+ parent.getChildAt(widgetCount - 1).requestFocus();
+ }
+ wasHandled = true;
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+
+ /**
+ * Private helper method to get the PagedViewCellLayoutChildren given a PagedViewCellLayout
+ * index.
+ */
+ private static PagedViewCellLayoutChildren getPagedViewCellLayoutChildrenForIndex(
+ ViewGroup container, int i) {
+ ViewGroup parent = (ViewGroup) container.getChildAt(i);
+ return (PagedViewCellLayoutChildren) parent.getChildAt(0);
+ }
+
+ /**
+ * Handles key events in a PageViewCellLayout containing PagedViewIcons.
+ */
+ static boolean handlePagedViewIconKeyEvent(PagedViewIcon v, int keyCode, KeyEvent e) {
+ final PagedViewCellLayoutChildren parent = (PagedViewCellLayoutChildren) v.getParent();
+ final PagedViewCellLayout parentLayout = (PagedViewCellLayout) parent.getParent();
+ // Note we have an extra parent because of the
+ // PagedViewCellLayout/PagedViewCellLayoutChildren relationship
+ final ViewGroup container = (ViewGroup) parentLayout.getParent();
+ final TabHost tabHost = findTabHostParent(container);
+ final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
+ final int widgetIndex = parent.indexOfChild(v);
+ final int widgetCount = parent.getChildCount();
+ final int pageIndex = container.indexOfChild(parentLayout);
+ final int pageCount = container.getChildCount();
+ final int cellCountX = parentLayout.getCellCountX();
+ final int cellCountY = parentLayout.getCellCountY();
+ final int x = widgetIndex % cellCountX;
+ final int y = widgetIndex / cellCountX;
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ PagedViewCellLayoutChildren newParent = null;
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (handleKeyEvent) {
+ // Select the previous icon or the last icon on the previous page
+ if (widgetIndex > 0) {
+ parent.getChildAt(widgetIndex - 1).requestFocus();
+ } else {
+ if (pageIndex > 0) {
+ newParent = getPagedViewCellLayoutChildrenForIndex(container,
+ pageIndex - 1);
+ newParent.getChildAt(newParent.getChildCount() - 1).requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ // Select the next icon or the first icon on the next page
+ if (widgetIndex < (widgetCount - 1)) {
+ parent.getChildAt(widgetIndex + 1).requestFocus();
+ } else {
+ if (pageIndex < (pageCount - 1)) {
+ newParent = getPagedViewCellLayoutChildrenForIndex(container,
+ pageIndex + 1);
+ newParent.getChildAt(0).requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (handleKeyEvent) {
+ // Select the closest icon in the previous row, otherwise select the tab bar
+ if (y > 0) {
+ int newWidgetIndex = ((y - 1) * cellCountX) + x;
+ parent.getChildAt(newWidgetIndex).requestFocus();
+ } else {
+ tabs.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (handleKeyEvent) {
+ // Select the closest icon in the previous row, otherwise do nothing
+ if (y < (cellCountY - 1)) {
+ int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
+ parent.getChildAt(newWidgetIndex).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ if (handleKeyEvent) {
+ // Simulate a click on the icon
+ View.OnClickListener clickListener = (View.OnClickListener) container;
+ clickListener.onClick(v);
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_PAGE_UP:
+ if (handleKeyEvent) {
+ // Select the first icon on the previous page, or the first icon on this page
+ // if there is no previous page
+ if (pageIndex > 0) {
+ newParent = getPagedViewCellLayoutChildrenForIndex(container,
+ pageIndex - 1);
+ newParent.getChildAt(0).requestFocus();
+ } else {
+ parent.getChildAt(0).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_PAGE_DOWN:
+ if (handleKeyEvent) {
+ // Select the first icon on the next page, or the last icon on this page
+ // if there is no next page
+ if (pageIndex < (pageCount - 1)) {
+ newParent = getPagedViewCellLayoutChildrenForIndex(container,
+ pageIndex + 1);
+ newParent.getChildAt(0).requestFocus();
+ } else {
+ parent.getChildAt(widgetCount - 1).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_MOVE_HOME:
+ if (handleKeyEvent) {
+ // Select the first icon on this page
+ parent.getChildAt(0).requestFocus();
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_MOVE_END:
+ if (handleKeyEvent) {
+ // Select the last icon on this page
+ parent.getChildAt(widgetCount - 1).requestFocus();
+ }
+ wasHandled = true;
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+
+ /**
+ * Handles key events in the tab widget.
+ */
+ static boolean handleTabKeyEvent(AccessibleTabView v, int keyCode, KeyEvent e) {
+ if (!LauncherApplication.isScreenLarge()) return false;
+
+ final FocusOnlyTabWidget parent = (FocusOnlyTabWidget) v.getParent();
+ final TabHost tabHost = findTabHostParent(parent);
+ final ViewGroup contents = (ViewGroup)
+ tabHost.findViewById(com.android.internal.R.id.tabcontent);
+ final int tabCount = parent.getTabCount();
+ final int tabIndex = parent.getChildTabIndex(v);
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (handleKeyEvent) {
+ // Select the previous tab
+ if (tabIndex > 0) {
+ parent.getChildTabViewAt(tabIndex - 1).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ // Select the next tab, or if the last tab has a focus right id, select that
+ if (tabIndex < (tabCount - 1)) {
+ parent.getChildTabViewAt(tabIndex + 1).requestFocus();
+ } else {
+ if (v.getNextFocusRightId() != View.NO_ID) {
+ tabHost.findViewById(v.getNextFocusRightId()).requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ // Do nothing
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (handleKeyEvent) {
+ // Select the content view
+ contents.requestFocus();
+ }
+ wasHandled = true;
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+
+ /**
+ * Handles key events in the workspace button bar.
+ */
+ static boolean handleButtonBarButtonKeyEvent(View v, int keyCode, KeyEvent e) {
+ if (!LauncherApplication.isScreenLarge()) return false;
+
+ final ViewGroup parent = (ViewGroup) v.getParent();
+ final ViewGroup launcher = (ViewGroup) parent.getParent();
+ final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
+ final int buttonIndex = parent.indexOfChild(v);
+ final int buttonCount = parent.getChildCount();
+ final int pageIndex = workspace.getCurrentPage();
+ final int pageCount = workspace.getChildCount();
+ final int firstButtonIndex = parent.indexOfChild(parent.findViewById(R.id.search_button));
+ final int lastButtonIndex = parent.indexOfChild(parent.findViewById(R.id.configure_button));
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (handleKeyEvent) {
+ // Select the previous button, otherwise do nothing (since the button bar is
+ // static)
+ if (buttonIndex > firstButtonIndex) {
+ int newButtonIndex = buttonIndex - 1;
+ while (newButtonIndex >= firstButtonIndex) {
+ View prev = parent.getChildAt(newButtonIndex);
+ if (isVisible(prev) && prev.isFocusable()) {
+ prev.requestFocus();
+ break;
+ }
+ --newButtonIndex;
+ }
+ } else {
+ if (pageIndex > 0) {
+ // Snap to previous page and clear focus
+ workspace.snapToPage(pageIndex - 1);
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ // Select the next button, otherwise do nothing (since the button bar is
+ // static)
+ if (buttonIndex < lastButtonIndex) {
+ int newButtonIndex = buttonIndex + 1;
+ while (newButtonIndex <= lastButtonIndex) {
+ View next = parent.getChildAt(newButtonIndex);
+ if (isVisible(next) && next.isFocusable()) {
+ next.requestFocus();
+ break;
+ }
+ ++newButtonIndex;
+ }
+ } else {
+ if (pageIndex < (pageCount - 1)) {
+ // Snap to next page and clear focus
+ workspace.snapToPage(pageIndex + 1);
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ // Do nothing
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (handleKeyEvent) {
+ // Select the first bubble text view in the current page of the workspace
+ final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
+ final CellLayoutChildren children = layout.getChildrenLayout();
+ final View newIcon = getBubbleTextViewInDirection(layout, children, -1, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ workspace.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+
+ /**
+ * Handles key events in the prev/next indicators.
+ */
+ static boolean handleIndicatorButtonKeyEvent(View v, int keyCode, KeyEvent e) {
+ final ViewGroup launcher = (ViewGroup) v.getParent();
+ final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
+ final ViewGroup hotseat = (ViewGroup) launcher.findViewById(R.id.all_apps_button_cluster);
+ final View previousIndicator = launcher.findViewById(R.id.previous_screen);
+ final View nextIndicator = launcher.findViewById(R.id.next_screen);
+ final int pageIndex = workspace.getCurrentPage();
+ final int pageCount = workspace.getChildCount();
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (handleKeyEvent) {
+ if (v == previousIndicator) {
+ if (pageIndex > 0) {
+ // Snap to previous page and clear focus
+ workspace.snapToPage(pageIndex - 1);
+ }
+ } else if (v == nextIndicator) {
+ // Select the last button in the hot seat
+ hotseat.getChildAt(hotseat.getChildCount() - 1).requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ if (v == previousIndicator) {
+ // Select the first button in the hot seat
+ hotseat.getChildAt(0).requestFocus();
+ } else if (v == nextIndicator) {
+ if (pageIndex < (pageCount - 1)) {
+ // Snap to next page and clear focus
+ workspace.snapToPage(pageIndex + 1);
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (handleKeyEvent) {
+ // Select the first bubble text view in the current page of the workspace
+ final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
+ final CellLayoutChildren children = layout.getChildrenLayout();
+ final View newIcon = getBubbleTextViewInDirection(layout, children, -1, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ workspace.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ // Do nothing
+ wasHandled = true;
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+
+ /**
+ * Handles key events in the workspace dock (bottom of the screen).
+ */
+ static boolean handleDockButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) {
+ final ViewGroup parent = (ViewGroup) v.getParent();
+ final ViewGroup launcher = (ViewGroup) parent.getParent();
+ final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
+ final int buttonIndex = parent.indexOfChild(v);
+ final int buttonCount = parent.getChildCount();
+ final int pageIndex = workspace.getCurrentPage();
+ final int pageCount = workspace.getChildCount();
+ final View previousIndicator = launcher.findViewById(R.id.previous_screen);
+ final View nextIndicator = launcher.findViewById(R.id.next_screen);
+
+ // NOTE: currently we don't special case for the phone UI in different
+ // orientations, even though the dock is on the side in landscape mode. This
+ // is to ensure that accessibility consistency is maintained across rotations.
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (handleKeyEvent) {
+
+ // Select the previous button, otherwise select the previous page indicator
+ if (buttonIndex > 0) {
+ parent.getChildAt(buttonIndex - 1).requestFocus();
+ } else {
+ previousIndicator.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ // Select the next button, otherwise select the next page indicator
+ if (buttonIndex < (buttonCount - 1)) {
+ parent.getChildAt(buttonIndex + 1).requestFocus();
+ } else {
+ nextIndicator.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (handleKeyEvent) {
+ // Select the first bubble text view in the current page of the workspace
+ final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
+ final CellLayoutChildren children = layout.getChildrenLayout();
+ final View newIcon = getBubbleTextViewInDirection(layout, children, -1, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ workspace.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ // Do nothing
+ wasHandled = true;
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+
+ /**
+ * Private helper method to get the CellLayoutChildren given a CellLayout index.
+ */
+ private static CellLayoutChildren getCellLayoutChildrenForIndex(ViewGroup container, int i) {
+ ViewGroup parent = (ViewGroup) container.getChildAt(i);
+ return (CellLayoutChildren) parent.getChildAt(0);
+ }
+
+ /**
+ * Private helper method to sort all the CellLayout children in order of their (x,y) spatially
+ * from top left to bottom right.
+ */
+ private static ArrayList<View> getCellLayoutChildrenSortedSpatially(CellLayout layout,
+ ViewGroup parent) {
+ // First we order each the CellLayout children by their x,y coordinates
+ final int cellCountX = layout.getCountX();
+ final int count = parent.getChildCount();
+ ArrayList<View> views = new ArrayList<View>();
+ for (int j = 0; j < count; ++j) {
+ views.add(parent.getChildAt(j));
+ }
+ Collections.sort(views, new Comparator<View>() {
+ @Override
+ public int compare(View lhs, View rhs) {
+ CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams();
+ CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams();
+ int lvIndex = (llp.cellY * cellCountX) + llp.cellX;
+ int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX;
+ return lvIndex - rvIndex;
+ }
+ });
+ return views;
+ }
+ /**
+ * Private helper method to find the index of the next BubbleTextView in the delta direction.
+ * @param delta either -1 or 1 depending on the direction we want to search
+ */
+ private static View findIndexOfBubbleTextView(ArrayList<View> views, int i, int delta) {
+ // Then we find the next BubbleTextView offset by delta from i
+ final int count = views.size();
+ int newI = i + delta;
+ while (0 <= newI && newI < count) {
+ View newV = views.get(newI);
+ if (newV instanceof BubbleTextView) {
+ return newV;
+ }
+ newI += delta;
+ }
+ return null;
+ }
+ private static View getBubbleTextViewInDirection(CellLayout layout, ViewGroup parent, int i,
+ int delta) {
+ final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
+ return findIndexOfBubbleTextView(views, i, delta);
+ }
+ private static View getBubbleTextViewInDirection(CellLayout layout, ViewGroup parent, View v,
+ int delta) {
+ final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
+ return findIndexOfBubbleTextView(views, views.indexOf(v), delta);
+ }
+ /**
+ * Private helper method to find the next closest BubbleTextView in the delta direction on the
+ * next line.
+ * @param delta either -1 or 1 depending on the line and direction we want to search
+ */
+ private static View getClosestBubbleTextViewOnLine(CellLayout layout, ViewGroup parent, View v,
+ int lineDelta) {
+ final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
+ final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
+ final int cellCountX = layout.getCountX();
+ final int cellCountY = layout.getCountY();
+ final int row = lp.cellY;
+ final int newRow = row + lineDelta;
+ if (0 <= newRow && newRow < cellCountY) {
+ float closestDistance = Float.MAX_VALUE;
+ int closestIndex = -1;
+ int index = views.indexOf(v);
+ int endIndex = (lineDelta < 0) ? -1 : views.size();
+ while (index != endIndex) {
+ View newV = views.get(index);
+ CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams();
+ boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row);
+ if (satisfiesRow && newV instanceof BubbleTextView) {
+ float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) +
+ Math.pow(tmpLp.cellY - lp.cellY, 2));
+ if (tmpDistance < closestDistance) {
+ closestIndex = index;
+ closestDistance = tmpDistance;
+ }
+ }
+ if (index <= endIndex) {
+ ++index;
+ } else {
+ --index;
+ }
+ }
+ if (closestIndex > -1) {
+ return views.get(closestIndex);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Handles key events in a Workspace containing BubbleTextView.
+ */
+ static boolean handleBubbleTextViewKeyEvent(BubbleTextView v, int keyCode, KeyEvent e) {
+ CellLayoutChildren parent = (CellLayoutChildren) v.getParent();
+ final CellLayout layout = (CellLayout) parent.getParent();
+ final Workspace workspace = (Workspace) layout.getParent();
+ final ViewGroup launcher = (ViewGroup) workspace.getParent();
+ final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.all_apps_button_cluster);
+ int iconIndex = parent.indexOfChild(v);
+ int iconCount = parent.getChildCount();
+ int pageIndex = workspace.indexOfChild(layout);
+ int pageCount = workspace.getChildCount();
+
+ final int action = e.getAction();
+ final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+ boolean wasHandled = false;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (handleKeyEvent) {
+ // Select the previous icon or the last icon on the previous page if possible
+ View newIcon = getBubbleTextViewInDirection(layout, parent, v, -1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ if (pageIndex > 0) {
+ parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
+ newIcon = getBubbleTextViewInDirection(layout, parent,
+ parent.getChildCount(), -1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ // Snap to the previous page
+ workspace.snapToPage(pageIndex - 1);
+ }
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (handleKeyEvent) {
+ // Select the next icon or the first icon on the next page if possible
+ View newIcon = getBubbleTextViewInDirection(layout, parent, v, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ if (pageIndex < (pageCount - 1)) {
+ parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
+ newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ // Snap to the next page
+ workspace.snapToPage(pageIndex + 1);
+ }
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (handleKeyEvent) {
+ // Select the closest icon in the previous line, otherwise select the tab bar
+ View newIcon = getClosestBubbleTextViewOnLine(layout, parent, v, -1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ wasHandled = true;
+ } else {
+ tabs.requestFocus();
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (handleKeyEvent) {
+ // Select the closest icon in the next line, otherwise select the tab bar
+ View newIcon = getClosestBubbleTextViewOnLine(layout, parent, v, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ wasHandled = true;
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_PAGE_UP:
+ if (handleKeyEvent) {
+ // Select the first icon on the previous page or the first icon on this page
+ // if there is no previous page
+ if (pageIndex > 0) {
+ parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
+ View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ // Snap to the previous page
+ workspace.snapToPage(pageIndex - 1);
+ }
+ } else {
+ View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_PAGE_DOWN:
+ if (handleKeyEvent) {
+ // Select the first icon on the next page or the last icon on this page
+ // if there is no previous page
+ if (pageIndex < (pageCount - 1)) {
+ parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
+ View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ } else {
+ // Snap to the next page
+ workspace.snapToPage(pageIndex + 1);
+ }
+ } else {
+ View newIcon = getBubbleTextViewInDirection(layout, parent,
+ parent.getChildCount(), -1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ }
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_MOVE_HOME:
+ if (handleKeyEvent) {
+ // Select the first icon on this page
+ View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ case KeyEvent.KEYCODE_MOVE_END:
+ if (handleKeyEvent) {
+ // Select the last icon on this page
+ View newIcon = getBubbleTextViewInDirection(layout, parent,
+ parent.getChildCount(), -1);
+ if (newIcon != null) {
+ newIcon.requestFocus();
+ }
+ }
+ wasHandled = true;
+ break;
+ default: break;
+ }
+ return wasHandled;
+ }
+}
diff --git a/src/com/android/launcher2/FocusOnlyTabWidget.java b/src/com/android/launcher2/FocusOnlyTabWidget.java
new file mode 100644
index 0000000..8e9f58c
--- /dev/null
+++ b/src/com/android/launcher2/FocusOnlyTabWidget.java
@@ -0,0 +1,86 @@
+/*
+ * 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.launcher2;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TabWidget;
+
+public class FocusOnlyTabWidget extends TabWidget {
+ public FocusOnlyTabWidget(Context context) {
+ super(context);
+ }
+
+ public FocusOnlyTabWidget(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public FocusOnlyTabWidget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public View getSelectedTab() {
+ final int count = getTabCount();
+ for (int i = 0; i < count; ++i) {
+ View v = getChildTabViewAt(i);
+ if (v.isSelected()) {
+ return v;
+ }
+ }
+ return null;
+ }
+
+ public int getChildTabIndex(View v) {
+ final int tabCount = getTabCount();
+ for (int i = 0; i < tabCount; ++i) {
+ if (getChildTabViewAt(i) == v) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public void setCurrentTabToFocusedTab() {
+ View tab = null;
+ int index = -1;
+ final int count = getTabCount();
+ for (int i = 0; i < count; ++i) {
+ View v = getChildTabViewAt(i);
+ if (v.hasFocus()) {
+ tab = v;
+ index = i;
+ break;
+ }
+ }
+ if (index > -1) {
+ super.setCurrentTab(index);
+ super.onFocusChange(tab, true);
+ }
+ }
+ public void superOnFocusChange(View v, boolean hasFocus) {
+ super.onFocusChange(v, hasFocus);
+ }
+
+ @Override
+ public void onFocusChange(android.view.View v, boolean hasFocus) {
+ if (v == this && hasFocus && getTabCount() > 0) {
+ getSelectedTab().requestFocus();
+ return;
+ }
+ }
+}
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 059e73d..3a8a68d 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -16,34 +16,45 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.AbsListView;
import android.widget.AdapterView;
-import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
+import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import com.android.launcher.R;
+import com.android.launcher2.FolderInfo.FolderListener;
+import com.android.launcher2.Workspace.ShrinkState;
/**
* Represents a set of icons chosen by the user or generated by the system.
*/
public class Folder extends LinearLayout implements DragSource, OnItemLongClickListener,
- OnItemClickListener, OnClickListener, View.OnLongClickListener {
+ OnItemClickListener, OnClickListener, View.OnLongClickListener, DropTarget, FolderListener {
- protected AbsListView mContent;
protected DragController mDragController;
-
+
protected Launcher mLauncher;
protected Button mCloseButton;
-
+
protected FolderInfo mInfo;
/**
@@ -51,6 +62,20 @@
*/
protected ShortcutInfo mDragItem;
+ private static final String TAG = "Launcher.Folder";
+
+ static final int STATE_NONE = -1;
+ static final int STATE_SMALL = 0;
+ static final int STATE_ANIMATING = 1;
+ static final int STATE_OPEN = 2;
+
+ private int mExpandDuration;
+ protected CellLayout mContent;
+ private final LayoutInflater mInflater;
+ private final IconCache mIconCache;
+ private int mState = STATE_NONE;
+ private int[] mDragItemPosition = new int[2];
+
/**
* Used to inflate the Workspace from XML.
*
@@ -60,19 +85,19 @@
public Folder(Context context, AttributeSet attrs) {
super(context, attrs);
setAlwaysDrawnWithCacheEnabled(false);
+ mInflater = LayoutInflater.from(context);
+ mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache();
+ mExpandDuration = getResources().getInteger(R.integer.config_folderAnimDuration);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mContent = (AbsListView) findViewById(R.id.folder_content);
- mContent.setOnItemClickListener(this);
- mContent.setOnItemLongClickListener(this);
-
mCloseButton = (Button) findViewById(R.id.folder_close);
mCloseButton.setOnClickListener(this);
mCloseButton.setOnLongClickListener(this);
+ mContent = (CellLayout) findViewById(R.id.folder_content);
}
public void onItemClick(AdapterView parent, View v, int position, long id) {
@@ -85,12 +110,47 @@
}
public void onClick(View v) {
- mLauncher.closeFolder(this);
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ // refactor this code from Folder
+ ShortcutInfo item = (ShortcutInfo) tag;
+ int[] pos = new int[2];
+ v.getLocationOnScreen(pos);
+ item.intent.setSourceBounds(new Rect(pos[0], pos[1],
+ pos[0] + v.getWidth(), pos[1] + v.getHeight()));
+ mLauncher.startActivitySafely(item.intent, item);
+ } else {
+ mLauncher.closeFolder(this);
+ }
}
public boolean onLongClick(View v) {
- mLauncher.closeFolder(this);
- mLauncher.showRenameDialog(mInfo);
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ // refactor this code from Folder
+ ShortcutInfo item = (ShortcutInfo) tag;
+ if (!v.isInTouchMode()) {
+ return false;
+ }
+
+ mLauncher.getWorkspace().onDragStartedWithItem(v);
+ mDragController.startDrag(v, this, item, DragController.DRAG_ACTION_COPY);
+ mDragItemPosition[0] = item.cellX;
+ mDragItemPosition[1] = item.cellY;
+ mLauncher.closeFolder(this);
+ mDragItem = item;
+ } else {
+ mLauncher.closeFolder(this);
+ mLauncher.showRenameDialog(mInfo);
+ }
+ return true;
+ }
+
+ /**
+ * We need to handle touch events to prevent them from falling through to the workspace below.
+ */
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
return true;
}
@@ -108,33 +168,13 @@
return true;
}
- @Override
public void setDragController(DragController dragController) {
mDragController = dragController;
}
- @Override
- public void onDropCompleted(View target, Object dragInfo, boolean success) {
- }
-
- @Override
public void onDragViewVisible() {
}
- /**
- * Sets the adapter used to populate the content area. The adapter must only
- * contains ShortcutInfo items.
- *
- * @param adapter The list of applications to display in the folder.
- */
- void setContentAdapter(BaseAdapter adapter) {
- mContent.setAdapter(adapter);
- }
-
- void notifyDataSetChanged() {
- ((BaseAdapter) mContent.getAdapter()).notifyDataSetChanged();
- }
-
void setLauncher(Launcher launcher) {
mLauncher = launcher;
}
@@ -146,10 +186,12 @@
return mInfo;
}
- // When the folder opens, we need to refresh the GridView's selection by
- // forcing a layout
void onOpen() {
+ // When the folder opens, we need to refresh the GridView's selection by
+ // forcing a layout
+ // TODO: find out if this is still necessary
mContent.requestLayout();
+ requestFocus();
}
void onClose() {
@@ -160,5 +202,245 @@
void bind(FolderInfo info) {
mInfo = info;
mCloseButton.setText(info.title);
+ ArrayList<ShortcutInfo> children = info.contents;
+ for (int i = 0; i < children.size(); i++) {
+ ShortcutInfo child = (ShortcutInfo) children.get(i);
+ if ((child.cellX == -1 && child.cellY == -1) ||
+ mContent.isOccupied(child.cellX, child.cellY)) {
+ findAndSetEmptyCells(child);
+ }
+ createAndAddShortcut((ShortcutInfo) children.get(i));
+ }
+ mInfo.addListener(this);
+ }
+
+ /**
+ * Creates a new UserFolder, inflated from R.layout.user_folder.
+ *
+ * @param context The application's context.
+ *
+ * @return A new UserFolder.
+ */
+ static Folder fromXml(Context context) {
+ return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
+ }
+
+ /**
+ * This method is intended to make the UserFolder to be visually identical in size and position
+ * to its associated FolderIcon. This allows for a seamless transition into the expanded state.
+ */
+ private void positionAndSizeAsIcon() {
+ if (!(getParent() instanceof CellLayoutChildren)) return;
+
+ CellLayoutChildren clc = (CellLayoutChildren) getParent();
+ CellLayout cellLayout = (CellLayout) clc.getParent();
+
+ FolderIcon fi = (FolderIcon) cellLayout.getChildAt(mInfo.cellX, mInfo.cellY);
+ CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) fi.getLayoutParams();
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+
+ lp.width = iconLp.width;
+ lp.height = iconLp.height;
+ lp.x = iconLp.x;
+ lp.y = iconLp.y;
+
+ mContent.setAlpha(0f);
+ mState = STATE_SMALL;
+ }
+
+ public void animateOpen() {
+ if (mState != STATE_SMALL) {
+ positionAndSizeAsIcon();
+ }
+ if (!(getParent() instanceof CellLayoutChildren)) return;
+
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+
+ CellLayoutChildren clc = (CellLayoutChildren) getParent();
+ CellLayout cellLayout = (CellLayout) clc.getParent();
+ Rect r = cellLayout.getContentRect(null);
+
+ PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", r.width());
+ PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", r.height());
+ PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", 0);
+ PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", 0);
+
+ ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
+ oa.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ requestLayout();
+ }
+ });
+
+ PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f);
+ ObjectAnimator oaContentAlpha = ObjectAnimator.ofPropertyValuesHolder(mContent, alpha);
+
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(oa, oaContentAlpha);
+ set.setDuration(mExpandDuration);
+ set.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mState = STATE_ANIMATING;
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mState = STATE_SMALL;
+ }
+ });
+ set.start();
+ }
+
+ public void animateClosed() {
+ if (!(getParent() instanceof CellLayoutChildren)) return;
+
+ CellLayoutChildren clc = (CellLayoutChildren) getParent();
+ final CellLayout cellLayout = (CellLayout) clc.getParent();
+
+ FolderIcon fi = (FolderIcon) cellLayout.getChildAt(mInfo.cellX, mInfo.cellY);
+ CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) fi.getLayoutParams();
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+
+ PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", iconLp.width);
+ PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", iconLp.height);
+ PropertyValuesHolder x = PropertyValuesHolder.ofInt("x",iconLp.x);
+ PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", iconLp.y);
+
+ ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
+ oa.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ requestLayout();
+ }
+ });
+
+ PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);
+ ObjectAnimator oaContentAlpha = ObjectAnimator.ofPropertyValuesHolder(mContent, alpha);
+
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(oa, oaContentAlpha);
+ set.setDuration(mExpandDuration);
+
+ set.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ cellLayout.removeViewWithoutMarkingCells(Folder.this);
+ mState = STATE_OPEN;
+ }
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mState = STATE_ANIMATING;
+ }
+ });
+ set.start();
+ }
+
+ void notifyDataSetChanged() {
+ // recreate all the children if the data set changes under us. We may want to do this more
+ // intelligently (ie just removing the views that should no longer exist)
+ mContent.removeAllViewsInLayout();
+ bind(mInfo);
+ }
+
+ public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ final ItemInfo item = (ItemInfo) dragInfo;
+ final int itemType = item.itemType;
+ return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+ itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT)
+ && item.container != mInfo.id;
+ }
+
+ public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ ShortcutInfo item;
+ if (dragInfo instanceof ApplicationInfo) {
+ // Came from all apps -- make a copy
+ item = ((ApplicationInfo)dragInfo).makeShortcut();
+ item.spanX = 1;
+ item.spanY = 1;
+ } else {
+ item = (ShortcutInfo)dragInfo;
+ }
+ findAndSetEmptyCells(item);
+ mInfo.add(item);
+ LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+ }
+
+ protected boolean findAndSetEmptyCells(ShortcutInfo item) {
+ int[] emptyCell = new int[2];
+ if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
+ item.cellX = emptyCell[0];
+ item.cellY = emptyCell[1];
+ LauncherModel.addOrMoveItemInDatabase(
+ mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected void createAndAddShortcut(ShortcutInfo item) {
+ final TextView textView =
+ (TextView) mInflater.inflate(R.layout.application_boxed, this, false);
+ textView.setCompoundDrawablesWithIntrinsicBounds(null,
+ new FastBitmapDrawable(item.getIcon(mIconCache)), null, null);
+ textView.setText(item.title);
+ textView.setTag(item);
+
+ textView.setOnClickListener(this);
+ textView.setOnLongClickListener(this);
+
+ CellLayout.LayoutParams lp =
+ new CellLayout.LayoutParams(item.cellX, item.cellY, item.spanX, item.spanY);
+ boolean insert = false;
+ mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true);
+ }
+
+ public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ }
+
+ public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ }
+
+ public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ }
+
+ public void onDropCompleted(View target, Object dragInfo, boolean success) {
+ if (success) {
+ mInfo.remove(mDragItem);
+ }
+ }
+
+ public boolean isDropEnabled() {
+ return true;
+ }
+
+ public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ return null;
+ }
+
+ public void onAdd(ShortcutInfo item) {
+ if ((item.cellX == -1 && item.cellY == -1) ||
+ mContent.isOccupied(item.cellX, item.cellY)) {
+ findAndSetEmptyCells(item);
+ }
+ createAndAddShortcut(item);
+ }
+
+ public int getItemCount() {
+ return mContent.getChildrenLayout().getChildCount();
+ }
+
+ public View getItemAt(int index) {
+ return mContent.getChildrenLayout().getChildAt(index);
+ }
+
+ public void onRemove(ShortcutInfo item) {
+ View v = mContent.getChildAt(mDragItemPosition[0], mDragItemPosition[1]);
+ mContent.removeView(v);
}
}
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index dd83c78..b770cd6 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -18,21 +18,27 @@
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.TextView;
import com.android.launcher.R;
+import com.android.launcher2.FolderInfo.FolderListener;
/**
* An icon that can appear on in the workspace representing an {@link UserFolder}.
*/
-public class FolderIcon extends BubbleTextView implements DropTarget {
- private UserFolderInfo mInfo;
+public class FolderIcon extends FrameLayout implements DropTarget, FolderListener {
private Launcher mLauncher;
- private Drawable mCloseIcon;
- private Drawable mOpenIcon;
+ Folder mFolder;
+ FolderInfo mInfo;
+
+ private static final int NUM_ITEMS_IN_PREVIEW = 4;
+ private static final float ICON_ANGLE = 15f;
public FolderIcon(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -43,25 +49,33 @@
}
public boolean isDropEnabled() {
- return !((Workspace)getParent().getParent()).isSmall();
+ final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
+ final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
+ final Workspace workspace = (Workspace) cellLayout.getParent();
+ return !workspace.isSmall();
}
static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
- UserFolderInfo folderInfo, IconCache iconCache) {
+ FolderInfo folderInfo, IconCache iconCache) {
FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
final Resources resources = launcher.getResources();
- Drawable d = iconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder);
- icon.mCloseIcon = d;
- icon.mOpenIcon = iconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder_open);
- icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);
- icon.setText(folderInfo.title);
+ Drawable d = iconCache.getFullResIcon(resources, R.drawable.folder_bg);
+ icon.setBackgroundDrawable(d);
icon.setTag(folderInfo);
icon.setOnClickListener(launcher);
icon.mInfo = folderInfo;
icon.mLauncher = launcher;
-
+
+ Folder folder = Folder.fromXml(launcher);
+ folder.setDragController(launcher.getDragController());
+ folder.setLauncher(launcher);
+ folder.bind(folderInfo);
+ icon.mFolder = folder;
+
+ folderInfo.addListener(icon);
+
return icon;
}
@@ -74,6 +88,11 @@
&& item.container != mInfo.id;
}
+ public void addItem(ShortcutInfo item) {
+ mInfo.add(item);
+ LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+ }
+
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
ShortcutInfo item;
@@ -83,15 +102,13 @@
} else {
item = (ShortcutInfo)dragInfo;
}
- mInfo.add(item);
- LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0);
+ item.cellX = -1;
+ item.cellY = -1;
+ addItem(item);
}
public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
- if (acceptDrop(source, x, y, xOffset, yOffset, dragView, dragInfo)) {
- setCompoundDrawablesWithIntrinsicBounds(null, mOpenIcon, null, null);
- }
}
public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
@@ -100,7 +117,6 @@
public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
- setCompoundDrawablesWithIntrinsicBounds(null, mCloseIcon, null, null);
}
@Override
@@ -108,4 +124,49 @@
DragView dragView, Object dragInfo) {
return null;
}
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mFolder == null) return;
+ if (mFolder.getItemCount() == 0) return;
+
+ canvas.save();
+ TextView v = (TextView) mFolder.getItemAt(0);
+ Drawable d = v.getCompoundDrawables()[1];
+
+ canvas.translate( (getMeasuredWidth() - d.getIntrinsicWidth()) / 2,
+ (getMeasuredHeight() - d.getIntrinsicHeight()) / 2);
+
+ canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
+ canvas.rotate(ICON_ANGLE);
+
+ canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
+
+ for (int i = Math.max(0, mFolder.getItemCount() - NUM_ITEMS_IN_PREVIEW);
+ i < mFolder.getItemCount(); i++) {
+ v = (TextView) mFolder.getItemAt(i);
+ d = v.getCompoundDrawables()[1];
+
+ if (d != null) {
+ d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
+ d.draw(canvas);
+ }
+
+ canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
+ canvas.rotate(-ICON_ANGLE);
+ canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
+ }
+
+ canvas.restore();
+ }
+
+ public void onAdd(ShortcutInfo item) {
+ invalidate();
+ requestLayout();
+ }
+
+ public void onRemove(ShortcutInfo item) {
+ invalidate();
+ requestLayout();
+ }
}
diff --git a/src/com/android/launcher2/FolderInfo.java b/src/com/android/launcher2/FolderInfo.java
index 8732690..12ed27c 100644
--- a/src/com/android/launcher2/FolderInfo.java
+++ b/src/com/android/launcher2/FolderInfo.java
@@ -16,12 +16,15 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
+import android.content.ContentValues;
/**
* Represents a folder containing shortcuts or apps.
*/
class FolderInfo extends ItemInfo {
-
+
/**
* Whether this folder has been opened
*/
@@ -31,4 +34,60 @@
* The folder name.
*/
CharSequence title;
+
+ /**
+ * The apps and shortcuts
+ */
+ ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
+
+ ArrayList<FolderListener> listeners = new ArrayList<FolderListener>();
+
+ FolderInfo() {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
+ }
+
+ /**
+ * Add an app or shortcut
+ *
+ * @param item
+ */
+ public void add(ShortcutInfo item) {
+ contents.add(item);
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).onAdd(item);
+ }
+ }
+
+ /**
+ * Remove an app or shortcut. Does not change the DB.
+ *
+ * @param item
+ */
+ public void remove(ShortcutInfo item) {
+ contents.remove(item);
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).onRemove(item);
+ }
+ }
+
+ @Override
+ void onAddToDatabase(ContentValues values) {
+ super.onAddToDatabase(values);
+ values.put(LauncherSettings.Favorites.TITLE, title.toString());
+ }
+
+ void addListener(FolderListener listener) {
+ listeners.add(listener);
+ }
+
+ void removeListener(FolderListener listener) {
+ if (listeners.contains(listener)) {
+ listeners.remove(listener);
+ }
+ }
+
+ interface FolderListener {
+ public void onAdd(ShortcutInfo item);
+ public void onRemove(ShortcutInfo item);
+ }
}
diff --git a/src/com/android/launcher2/HolographicPagedViewIcon.java b/src/com/android/launcher2/HolographicPagedViewIcon.java
index 5e18169..7123e2a 100644
--- a/src/com/android/launcher2/HolographicPagedViewIcon.java
+++ b/src/com/android/launcher2/HolographicPagedViewIcon.java
@@ -41,7 +41,6 @@
@Override
protected void onDraw(Canvas canvas) {
Bitmap overlay = mOriginalIcon.getHolographicOutline();
-
if (overlay != null) {
final int offset = getScrollX();
final int compoundPaddingLeft = getCompoundPaddingLeft();
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
index 0c26bf0..7e37afe 100644
--- a/src/com/android/launcher2/IconCache.java
+++ b/src/com/android/launcher2/IconCache.java
@@ -54,7 +54,7 @@
mContext = context;
mPackageManager = context.getPackageManager();
mBubble = new Utilities.BubbleText(context);
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
mIconDpi = DisplayMetrics.DENSITY_HIGH;
} else {
mIconDpi = context.getResources().getDisplayMetrics().densityDpi;
diff --git a/src/com/android/launcher2/IconDropTarget.java b/src/com/android/launcher2/IconDropTarget.java
index fb5d0f0..4d018e6 100644
--- a/src/com/android/launcher2/IconDropTarget.java
+++ b/src/com/android/launcher2/IconDropTarget.java
@@ -126,7 +126,7 @@
@Override
public void getHitRect(Rect outRect) {
super.getHitRect(outRect);
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
outRect.top -= mDragPadding[0];
outRect.right += mDragPadding[1];
outRect.bottom += mDragPadding[2];
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index b361214..3bb3b07 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -38,7 +38,7 @@
/**
* One of {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
* {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
- * {@link LauncherSettings.Favorites#ITEM_TYPE_USER_FOLDER}, or
+ * {@link LauncherSettings.Favorites#ITEM_TYPE_FOLDER}, or
* {@link LauncherSettings.Favorites#ITEM_TYPE_APPWIDGET}.
*/
int itemType;
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index b7f04f7..2fe1c7d 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -17,9 +17,13 @@
package com.android.launcher2;
-import com.android.common.Search;
-import com.android.launcher.R;
-import com.android.launcher2.Workspace.ShrinkState;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -63,10 +67,8 @@
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
-import android.os.Parcelable;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.provider.LiveFolders;
import android.provider.Settings;
import android.speech.RecognizerIntent;
import android.text.Selection;
@@ -99,14 +101,9 @@
import android.widget.TextView;
import android.widget.Toast;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
+import com.android.common.Search;
+import com.android.launcher.R;
+import com.android.launcher2.Workspace.ShrinkState;
/**
* Default launcher application.
@@ -132,11 +129,9 @@
private static final int MENU_SETTINGS = MENU_NOTIFICATIONS + 1;
private static final int REQUEST_CREATE_SHORTCUT = 1;
- private static final int REQUEST_CREATE_LIVE_FOLDER = 4;
private static final int REQUEST_CREATE_APPWIDGET = 5;
private static final int REQUEST_PICK_APPLICATION = 6;
private static final int REQUEST_PICK_SHORTCUT = 7;
- private static final int REQUEST_PICK_LIVE_FOLDER = 8;
private static final int REQUEST_PICK_APPWIDGET = 9;
private static final int REQUEST_PICK_WALLPAPER = 10;
@@ -155,7 +150,7 @@
// Type: int
private static final String RUNTIME_STATE = "launcher.state";
// Type: long
- private static final String RUNTIME_STATE_USER_FOLDERS = "launcher.user_folder";
+ private static final String RUNTIME_STATE_FOLDERS = "launcher.folder";
// Type: int
private static final String RUNTIME_STATE_PENDING_ADD_SCREEN = "launcher.add_screen";
// Type: int
@@ -170,7 +165,7 @@
private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
/** The different states that Launcher can be in. */
- private enum State { WORKSPACE, ALL_APPS, CUSTOMIZE,
+ private enum State { WORKSPACE, APPS_CUSTOMIZE, ALL_APPS, CUSTOMIZE,
CUSTOMIZE_SPRING_LOADED, ALL_APPS_SPRING_LOADED };
private State mState = State.WORKSPACE;
private AnimatorSet mStateAnimation;
@@ -203,10 +198,12 @@
private DeleteZone mDeleteZone;
private HandleView mHandleView;
private AllAppsView mAllAppsGrid;
+ private AppsCustomizeTabHost mAppsCustomizeTabHost;
+ private AppsCustomizePagedView mAppsCustomizeContent;
private CustomizeTrayTabHost mHomeCustomizationDrawer;
private boolean mAutoAdvanceRunning = false;
- private View mButtonCluster;
+ private ViewGroup mButtonCluster;
private View mAllAppsButton;
private View mDivider;
private View mConfigureButton;
@@ -315,7 +312,6 @@
// share the same customization workspace across all the tabs
mCustomizePagedView = (CustomizePagedView) findViewById(
R.id.customization_drawer_tab_contents);
-
}
setupViews();
@@ -330,6 +326,9 @@
if (mCustomizePagedView != null) {
mCustomizePagedView.update();
}
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.onPackagesUpdated();
+ }
if (PROFILE_STARTUP) {
android.os.Debug.stopMethodTracing();
@@ -347,7 +346,7 @@
registerReceiver(mCloseSystemDialogsReceiver, filter);
// If we have a saved version of these external icons, we load them up immediately
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
if (sGlobalSearchIcon == null || sVoiceSearchIcon == null || sAppMarketIcon == null) {
updateIconsAffectedByPackageManagerChanges();
}
@@ -363,21 +362,6 @@
}
}
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- super.dispatchPopulateAccessibilityEvent(event);
-
- // we want to take over text population so it is context dependent
- event.getText().clear();
- if (mState == State.ALL_APPS) {
- event.getText().add(getString(R.string.all_apps_button_label));
- } else if (mState == State.WORKSPACE) {
- event.getText().add(getString(R.string.all_apps_home_button_label));
- }
-
- return true;
- }
-
private void checkForLocaleChange() {
if (sLocaleConfiguration == null) {
new AsyncTask<Void, Void, LocaleConfiguration>() {
@@ -648,12 +632,6 @@
case REQUEST_CREATE_SHORTCUT:
completeAddShortcut(args.intent, args.screen, args.cellX, args.cellY);
break;
- case REQUEST_PICK_LIVE_FOLDER:
- addLiveFolder(args.intent);
- break;
- case REQUEST_CREATE_LIVE_FOLDER:
- completeAddLiveFolder(args.intent, args.screen, args.cellX, args.cellY);
- break;
case REQUEST_PICK_APPWIDGET:
addAppWidgetFromPick(args.intent);
break;
@@ -738,7 +716,12 @@
public Object onRetainNonConfigurationInstance() {
// Flag the loader to stop early before switching
mModel.stopLoader();
- mAllAppsGrid.surrender();
+ if (mAllAppsGrid != null) {
+ mAllAppsGrid.surrender();
+ }
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.surrender();
+ }
return Boolean.TRUE;
}
@@ -771,8 +754,10 @@
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- boolean handled = super.onKeyDown(keyCode, event);
- if (!handled && acceptFilter() && keyCode != KeyEvent.KEYCODE_ENTER) {
+ final int uniChar = event.getUnicodeChar();
+ final boolean handled = super.onKeyDown(keyCode, event);
+ final boolean isKeyNotWhitespace = uniChar > 0 && !Character.isWhitespace(uniChar);
+ if (!handled && acceptFilter() && isKeyNotWhitespace) {
boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb,
keyCode, event);
if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) {
@@ -832,7 +817,7 @@
State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
- if (state == State.ALL_APPS) {
+ if (state == State.ALL_APPS || state == State.APPS_CUSTOMIZE) {
showAllApps(false);
} else if (state == State.CUSTOMIZE) {
showCustomizationDrawer(false);
@@ -885,6 +870,20 @@
// Note: currently we do not restore the page for the customization tray because unlike
// AllApps, the page content can change drastically
}
+
+ // Restore the AppsCustomize tab
+ if (mAppsCustomizeTabHost != null) {
+ String curTab = savedState.getString("apps_customize_currentTab");
+ if (curTab != null) {
+ // We set this directly so that there is no delay before the tab is set
+ mAppsCustomizeContent.setContentType(
+ mAppsCustomizeTabHost.getContentTypeForTabTag(curTab));
+ mAppsCustomizeTabHost.setCurrentTabByTag(curTab);
+ }
+
+ // Note: currently we do not restore the page for the AppsCustomize pane because the
+ // change in layout can drastically affect the saved page index
+ }
}
/**
@@ -896,18 +895,17 @@
DragLayer dragLayer = (DragLayer) findViewById(R.id.drag_layer);
dragLayer.setDragController(dragController);
- mAllAppsGrid = (AllAppsView)dragLayer.findViewById(R.id.all_apps_view);
- mAllAppsGrid.setLauncher(this);
- mAllAppsGrid.setDragController(dragController);
- ((View) mAllAppsGrid).setWillNotDraw(false); // We don't want a hole punched in our window.
- // Manage focusability manually since this thing is always visible (in non-xlarge)
- ((View) mAllAppsGrid).setFocusable(false);
-
- if (LauncherApplication.isScreenXLarge()) {
- // They need to be INVISIBLE initially so that they will be measured in the layout.
- // Otherwise the animations are messed up when we show them for the first time.
- ((View) mAllAppsGrid).setVisibility(View.INVISIBLE);
- mHomeCustomizationDrawer.setVisibility(View.INVISIBLE);
+ if (LauncherApplication.isScreenLarge()) {
+ mAllAppsGrid = (AllAppsView) dragLayer.findViewById(R.id.all_apps_view);
+ mAllAppsGrid.setup(this, dragController);
+ // We don't want a hole punched in our window.
+ ((View) mAllAppsGrid).setWillNotDraw(false);
+ } else {
+ mAppsCustomizeTabHost = (AppsCustomizeTabHost)
+ findViewById(R.id.apps_customize_pane);
+ mAppsCustomizeContent = (AppsCustomizePagedView)
+ mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
+ mAppsCustomizeContent.setup(this, dragController);
}
mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
@@ -923,7 +921,6 @@
// we don't use handle view in xlarge mode
mHandleView = (HandleView)handleView;
mHandleView.setLauncher(this);
- mHandleView.setOnClickListener(this);
mHandleView.setOnLongClickListener(this);
}
@@ -938,8 +935,11 @@
hotseatRight.setContentDescription(mHotseatLabels[1]);
hotseatRight.setImageDrawable(mHotseatIcons[1]);
+ View.OnKeyListener listener = new IndicatorKeyEventListener();
mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
+ mPreviousView.setOnKeyListener(listener);
mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
+ mNextView.setOnKeyListener(listener);
Drawable previous = mPreviousView.getDrawable();
Drawable next = mNextView.getDrawable();
@@ -960,10 +960,10 @@
deleteZone.setDragController(dragController);
final View allAppsButton = findViewById(R.id.all_apps_button);
- final View divider = findViewById(R.id.divider);
+ final View divider = findViewById(R.id.all_apps_divider);
final View configureButton = findViewById(R.id.configure_button);
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
deleteZone.setOverlappingViews(new View[] { allAppsButton, divider, configureButton });
} else {
deleteZone.setOverlappingView(findViewById(R.id.all_apps_button_cluster));
@@ -985,15 +985,17 @@
allAppsInfoTarget.setLauncher(this);
dragController.addDragListener(allAppsInfoTarget);
allAppsInfoTarget.setDragAndDropEnabled(false);
- View marketButton = findViewById(R.id.market_button);
- if (marketButton != null) {
+ }
+ View marketButton = findViewById(R.id.market_button);
+ if (marketButton != null) {
+ if (allAppsInfoTarget != null) {
allAppsInfoTarget.setOverlappingView(marketButton);
- marketButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- onClickAppMarketButton(v);
- }
- });
}
+ marketButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ onClickAppMarketButton(v);
+ }
+ });
}
dragController.setDragScoller(workspace);
@@ -1009,10 +1011,22 @@
if (allAppsDeleteZone != null) {
dragController.addDropTarget(allAppsDeleteZone);
}
- mButtonCluster = findViewById(R.id.all_apps_button_cluster);
+ mButtonCluster = (ViewGroup) findViewById(R.id.all_apps_button_cluster);
+ View.OnKeyListener listener = null;
+ if (LauncherApplication.isScreenLarge()) {
+ // For tablets, AllApps lives in the button bar at the top
+ listener = new ButtonBarKeyEventListener();
+ } else {
+ // For phones, AppsCustomize lives in the "dock" at the bottom
+ listener = new DockKeyEventListener();
+ }
+ int buttonCount = mButtonCluster.getChildCount();
+ for (int i = 0; i < buttonCount; ++i) {
+ mButtonCluster.getChildAt(i).setOnKeyListener(listener);
+ }
mAllAppsButton = findViewById(R.id.all_apps_button);
- mDivider = findViewById(R.id.divider);
+ mDivider = findViewById(R.id.all_apps_divider);
mConfigureButton = findViewById(R.id.configure_button);
// We had previously set these click handlers in XML, but the first time we launched
@@ -1043,14 +1057,14 @@
@SuppressWarnings({"UnusedDeclaration"})
public void previousScreen(View v) {
- if (mState != State.ALL_APPS) {
+ if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
mWorkspace.scrollLeft();
}
}
@SuppressWarnings({"UnusedDeclaration"})
public void nextScreen(View v) {
- if (mState != State.ALL_APPS) {
+ if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
mWorkspace.scrollRight();
}
}
@@ -1253,6 +1267,14 @@
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
mUserPresent = false;
updateRunning();
+
+ // Reset AllApps to it's initial state
+ if (mAllAppsGrid != null) {
+ mAllAppsGrid.reset();
+ }
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.reset();
+ }
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
mUserPresent = true;
updateRunning();
@@ -1407,11 +1429,7 @@
!= Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
// In all these cases, only animate if we're already on home
-
- if (LauncherApplication.isScreenXLarge()) {
- mWorkspace.unshrink(alreadyOnHome);
- }
-
+ mWorkspace.unshrink(alreadyOnHome);
mWorkspace.exitWidgetResizeMode();
if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive()) {
mWorkspace.moveToDefaultScreen(true);
@@ -1424,6 +1442,14 @@
INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
+
+ // Reset AllApps to it's initial state
+ if (mAllAppsGrid != null) {
+ mAllAppsGrid.reset();
+ }
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.reset();
+ }
}
}
@@ -1445,7 +1471,7 @@
final FolderInfo info = folders.get(i).getInfo();
ids[i] = info.id;
}
- outState.putLongArray(RUNTIME_STATE_USER_FOLDERS, ids);
+ outState.putLongArray(RUNTIME_STATE_FOLDERS, ids);
} else {
super.onSaveInstanceState(outState);
}
@@ -1472,7 +1498,6 @@
outState.putInt("allapps_currentPage", mAllAppsPagedView.getCurrentPage());
}
}
-
// Save the current customization drawer tab
if (mHomeCustomizationDrawer != null) {
String currentTabTag = mHomeCustomizationDrawer.getCurrentTabTag();
@@ -1480,6 +1505,13 @@
outState.putString("customize_currentTab", currentTabTag);
}
}
+ // Save the current AppsCustomize tab
+ if (mAppsCustomizeTabHost != null) {
+ String currentTabTag = mAppsCustomizeTabHost.getCurrentTabTag();
+ if (currentTabTag != null) {
+ outState.putString("apps_customize_currentTab", currentTabTag);
+ }
+ }
}
@Override
@@ -1521,6 +1553,10 @@
ValueAnimator.clearAllAnimations();
}
+ public DragController getDragController() {
+ return mDragController;
+ }
+
@Override
public void startActivityForResult(Intent intent, int requestCode) {
if (requestCode >= 0) mWaitingForResult = true;
@@ -1588,22 +1624,28 @@
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- // If all apps is animating, don't show the menu, because we don't know
- // which one to show.
- if (mAllAppsGrid.isAnimating()) {
- return false;
+ if (mAllAppsGrid != null) {
+ // If all apps is animating, don't show the menu, because we don't know
+ // which one to show.
+ if (mAllAppsGrid.isAnimating()) {
+ return false;
+ }
+
+ // Only show the add and wallpaper options when we're not in all apps.
+ boolean visible = !mAllAppsGrid.isVisible();
+ menu.setGroupVisible(MENU_GROUP_ADD, visible);
+ menu.setGroupVisible(MENU_GROUP_WALLPAPER, visible);
+
+ // Disable add if the workspace is full.
+ if (visible) {
+ CellLayout layout = (CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
+ menu.setGroupEnabled(MENU_GROUP_ADD, layout.existsEmptyCell());
+ }
}
- // Only show the add and wallpaper options when we're not in all apps.
- boolean visible = !mAllAppsGrid.isVisible();
- menu.setGroupVisible(MENU_GROUP_ADD, visible);
- menu.setGroupVisible(MENU_GROUP_WALLPAPER, visible);
-
- // Disable add if the workspace is full.
- if (visible) {
- CellLayout layout = (CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
- menu.setGroupEnabled(MENU_GROUP_ADD, layout.existsEmptyCell());
- }
+ // TODO-APPS_CUSTOMIZE: Remove this for the phone UI at some point, along with all the menu
+ // related code?
+ if (mAppsCustomizeContent != null && mAppsCustomizeContent.isAnimating()) return false;
return true;
}
@@ -1653,7 +1695,7 @@
}
private void addItems() {
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
// Animate the widget chooser up from the bottom of the screen
if (mState != State.CUSTOMIZE) {
showCustomizationDrawer(true);
@@ -1770,38 +1812,15 @@
startActivityForResult(intent, REQUEST_PICK_WALLPAPER);
}
- void addLiveFolderFromDrop(ComponentName componentName, int screen, int[] position) {
- resetAddInfo();
- mAddScreen = screen;
- mAddDropPosition = position;
-
- Intent createFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
- createFolderIntent.setComponent(componentName);
-
- addLiveFolder(createFolderIntent);
- }
-
- void addLiveFolder(Intent intent) { // YYY add screen intersect etc. parameters here
- // Handle case where user selected "Folder"
- String folderName = getResources().getString(R.string.group_folder);
- String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
-
- if (folderName != null && folderName.equals(shortcutName)) {
- addFolder(mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
- } else {
- startActivityForResultSafely(intent, REQUEST_CREATE_LIVE_FOLDER);
- }
- }
-
- void addFolder(int screen, int intersectCellX, int intersectCellY) {
- UserFolderInfo folderInfo = new UserFolderInfo();
+ FolderIcon addFolder(int screen, int intersectCellX, int intersectCellY) {
+ FolderInfo folderInfo = new FolderInfo();
folderInfo.title = getText(R.string.folder_name);
final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
final int[] cellXY = mTmpAddItemCellCoordinates;
if (!layout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectCellX, intersectCellY)) {
showOutOfSpaceMessage();
- return;
+ return null;
}
// Update the model
@@ -1815,73 +1834,13 @@
(ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()),
folderInfo, mIconCache);
mWorkspace.addInScreen(newFolder, screen, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked());
+ return newFolder;
}
void removeFolder(FolderInfo folder) {
sFolders.remove(folder.id);
}
- private void completeAddLiveFolder(
- Intent data, int screen, int intersectCellX, int intersectCellY) {
- final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
- final int[] cellXY = mTmpAddItemCellCoordinates;
- if (!layout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectCellX, intersectCellY)) {
- showOutOfSpaceMessage();
- return;
- }
-
- final LiveFolderInfo info = addLiveFolder(this, data, screen, cellXY[0], cellXY[1], false);
-
- if (!mRestoring) {
- final View view = LiveFolderIcon.fromXml(R.layout.live_folder_icon, this,
- (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
- mWorkspace.addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked());
- }
- }
-
- static LiveFolderInfo addLiveFolder(Context context, Intent data,
- int screen, int cellX, int cellY, boolean notify) {
-
- Intent baseIntent = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT);
- String name = data.getStringExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME);
-
- Drawable icon = null;
- Intent.ShortcutIconResource iconResource = null;
-
- Parcelable extra = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON);
- if (extra != null && extra instanceof Intent.ShortcutIconResource) {
- try {
- iconResource = (Intent.ShortcutIconResource) extra;
- final PackageManager packageManager = context.getPackageManager();
- Resources resources = packageManager.getResourcesForApplication(
- iconResource.packageName);
- final int id = resources.getIdentifier(iconResource.resourceName, null, null);
- icon = resources.getDrawable(id);
- } catch (Exception e) {
- Log.w(TAG, "Could not load live folder icon: " + extra);
- }
- }
-
- if (icon == null) {
- icon = context.getResources().getDrawable(R.drawable.ic_launcher_folder);
- }
-
- final LiveFolderInfo info = new LiveFolderInfo();
- info.icon = Utilities.createIconBitmap(icon, context);
- info.title = name;
- info.iconResource = iconResource;
- info.uri = data.getData();
- info.baseIntent = baseIntent;
- info.displayMode = data.getIntExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,
- LiveFolders.DISPLAY_MODE_GRID);
-
- LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
- screen, cellX, cellY, notify);
- sFolders.put(info.id, info);
-
- return info;
- }
-
private void showNotifications() {
final StatusBarManager statusBar = (StatusBarManager) getSystemService(STATUS_BAR_SERVICE);
if (statusBar != null) {
@@ -1943,7 +1902,7 @@
@Override
public void onBackPressed() {
- if (mState == State.ALL_APPS || mState == State.CUSTOMIZE) {
+ if (mState == State.ALL_APPS || mState == State.CUSTOMIZE || mState == State.APPS_CUSTOMIZE) {
showWorkspace(true);
} else if (mWorkspace.getOpenFolder() != null) {
closeFolder();
@@ -1967,15 +1926,14 @@
void closeFolder(Folder folder) {
folder.getInfo().opened = false;
+
ViewGroup parent = (ViewGroup) folder.getParent().getParent();
if (parent != null) {
CellLayout cl = (CellLayout) parent;
- cl.removeViewWithoutMarkingCells(folder);
- if (folder instanceof DropTarget) {
- // Live folders aren't DropTargets.
- mDragController.removeDropTarget((DropTarget)folder);
- }
+ mDragController.removeDropTarget((DropTarget)folder);
}
+
+ folder.animateClosed();
folder.onClose();
}
@@ -2020,7 +1978,10 @@
mWaitingForResume.setStayPressed(true);
}
} else if (tag instanceof FolderInfo) {
- handleFolderClick((FolderInfo) tag);
+ if (v instanceof FolderIcon) {
+ FolderIcon fi = (FolderIcon) v;
+ handleFolderClick(fi);
+ }
} else if (v == mHandleView) {
if (mState == State.ALL_APPS) {
showWorkspace(true);
@@ -2142,15 +2103,16 @@
}
}
- private void handleFolderClick(FolderInfo folderInfo) {
- if (!folderInfo.opened) {
+ private void handleFolderClick(FolderIcon folderIcon) {
+ final FolderInfo info = folderIcon.mInfo;
+ if (!info.opened) {
// Close any open folder
closeFolder();
// Open the requested folder
- openFolder(folderInfo);
+ openFolder(folderIcon);
} else {
// Find the open folder...
- Folder openFolder = mWorkspace.getFolderForTag(folderInfo);
+ Folder openFolder = mWorkspace.getFolderForTag(info);
int folderScreen;
if (openFolder != null) {
folderScreen = mWorkspace.getPageForView(openFolder);
@@ -2160,7 +2122,7 @@
// Close any folder open on the current screen
closeFolder();
// Pull the folder onto this screen
- openFolder(folderInfo);
+ openFolder(folderIcon);
}
}
}
@@ -2173,26 +2135,15 @@
*
* @param folderInfo The FolderInfo describing the folder to open.
*/
- public void openFolder(FolderInfo folderInfo) {
- Folder openFolder;
+ public void openFolder(FolderIcon folderIcon) {
+ Folder folder = folderIcon.mFolder;
+ FolderInfo info = folder.mInfo;
- if (folderInfo instanceof UserFolderInfo) {
- openFolder = UserFolder.fromXml(this);
- } else if (folderInfo instanceof LiveFolderInfo) {
- openFolder = com.android.launcher2.LiveFolder.fromXml(this, folderInfo);
- } else {
- return;
- }
+ info.opened = true;
- openFolder.setDragController(mDragController);
- openFolder.setLauncher(this);
-
- openFolder.bind(folderInfo);
- folderInfo.opened = true;
-
- mWorkspace.addInFullScreen(openFolder, folderInfo.screen);
-
- openFolder.onOpen();
+ mWorkspace.addInFullScreen(folder, info.screen);
+ folder.animateOpen();
+ folder.onOpen();
}
public boolean onLongClick(View v) {
@@ -2202,21 +2153,21 @@
switch (v.getId()) {
case R.id.previous_screen:
- if (mState != State.ALL_APPS) {
+ if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
showPreviews(v);
}
return true;
case R.id.next_screen:
- if (mState != State.ALL_APPS) {
+ if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
showPreviews(v);
}
return true;
case R.id.all_apps_button:
- if (mState != State.ALL_APPS) {
+ if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
showPreviews(v);
@@ -2247,10 +2198,10 @@
mWorkspace.setAllowLongPress(false);
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
addItems();
} else {
- showAddDialog(longClickCellInfo.cellX, longClickCellInfo.cellY);
+ startWallpaper();
}
} else {
if (!(itemUnderLongClick instanceof Folder)) {
@@ -2277,11 +2228,12 @@
for (int i = 0; i < count; i++) {
((ImageView) group.getChildAt(i)).setImageDrawable(null);
}
- ArrayList<Bitmap> bitmaps = (ArrayList<Bitmap>) v.getTag(R.id.icon);
+ ArrayList<Bitmap> bitmaps =
+ (ArrayList<Bitmap>) v.getTag(R.id.all_apps_button_cluster);
for (Bitmap bitmap : bitmaps) bitmap.recycle();
v.setTag(R.id.workspace, null);
- v.setTag(R.id.icon, null);
+ v.setTag(R.id.all_apps_button_cluster, null);
window.setOnDismissListener(null);
}
});
@@ -2373,7 +2325,7 @@
anchor.setTag(p);
anchor.setTag(R.id.workspace, preview);
- anchor.setTag(R.id.icon, bitmaps);
+ anchor.setTag(R.id.all_apps_button_cluster, bitmaps);
}
class PreviewTouchHandler implements View.OnClickListener, Runnable, View.OnFocusChangeListener {
@@ -2532,7 +2484,9 @@
final FolderIcon folderIcon = (FolderIcon)
mWorkspace.getViewForTag(mFolderInfo);
if (folderIcon != null) {
- folderIcon.setText(name);
+ // TODO: At some point we'll probably want some version of setting
+ // the text for a folder icon.
+ //folderIcon.setText(name);
getWorkspace().requestLayout();
} else {
lockAllApps();
@@ -2553,32 +2507,25 @@
// Now a part of LauncherModel.Callbacks. Used to reorder loading steps.
public boolean isAllAppsVisible() {
- return mState == State.ALL_APPS;
+ return (mState == State.ALL_APPS) || (mState == State.APPS_CUSTOMIZE);
}
// AllAppsView.Watcher
public void zoomed(float zoom) {
// In XLarge view, we zoom down the workspace below all apps so it's still visible
- if (zoom == 1.0f && !LauncherApplication.isScreenXLarge()) {
+ if (zoom == 1.0f && !LauncherApplication.isScreenLarge()) {
mWorkspace.setVisibility(View.GONE);
}
}
private void showAndEnableToolbarButton(View button) {
button.setVisibility(View.VISIBLE);
- button.setFocusable(true);
- button.setClickable(true);
}
private void hideToolbarButton(View button) {
- button.setAlpha(0.0f);
// We can't set it to GONE, otherwise the RelativeLayout gets screwed up
button.setVisibility(View.INVISIBLE);
- }
-
- private void disableToolbarButton(View button) {
- button.setFocusable(false);
- button.setClickable(false);
+ button.setAlpha(0.0f);
}
/**
@@ -2609,7 +2556,6 @@
@Override
public void onAnimationStart(Animator animation) {
if (showing) showAndEnableToolbarButton(view);
- if (hiding) disableToolbarButton(view);
}
@Override
public void onAnimationEnd(Animator animation) {
@@ -2622,7 +2568,6 @@
showAndEnableToolbarButton(view);
view.setAlpha(1f);
} else {
- disableToolbarButton(view);
hideToolbarButton(view);
}
}
@@ -2640,15 +2585,18 @@
switch (newState) {
case WORKSPACE:
hideOrShowToolbarButton(true, mButtonCluster, showSeq);
- mDeleteZone.setOverlappingViews(
- new View[] { mAllAppsButton, mDivider, mConfigureButton });
mDeleteZone.setDragAndDropEnabled(true);
- mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_workspace));
+ if (LauncherApplication.isScreenLarge()) {
+ mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_workspace));
+ }
break;
case ALL_APPS:
+ case APPS_CUSTOMIZE:
hideOrShowToolbarButton(false, mButtonCluster, hideSeq);
mDeleteZone.setDragAndDropEnabled(false);
- mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_all_apps));
+ if (LauncherApplication.isScreenLarge()) {
+ mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_all_apps));
+ }
break;
case CUSTOMIZE:
hideOrShowToolbarButton(false, mButtonCluster, hideSeq);
@@ -2670,7 +2618,7 @@
// Set pivotY so that at the starting zoom factor, the view is partially
// visible. Modifying initialHeightFactor changes how much of the view is
// initially showing, and hence the perceived angle from which the view enters.
- if (state == State.ALL_APPS) {
+ if (state == State.ALL_APPS || state == State.APPS_CUSTOMIZE) {
final float initialHeightFactor = 0.175f;
view.setPivotY((1 - initialHeightFactor) * height);
} else {
@@ -2685,27 +2633,45 @@
* of the screen.
* @param toState The state to zoom out to. Must be ALL_APPS or CUSTOMIZE.
*/
- private void cameraZoomOut(State toState, boolean animated) {
+ private void cameraZoomOut(State toState, boolean animated, boolean springLoaded) {
final Resources res = getResources();
- final boolean toAllApps = (toState == State.ALL_APPS);
+ final boolean toAllApps = (toState == State.ALL_APPS)
+ || (toState == State.APPS_CUSTOMIZE);
- final int duration = toAllApps ?
- res.getInteger(R.integer.config_allAppsZoomInTime) :
- res.getInteger(R.integer.config_customizeZoomInTime);
- final int fadeDuration = toAllApps ?
- res.getInteger(R.integer.config_allAppsFadeInTime) :
- res.getInteger(R.integer.config_customizeFadeInTime);
+ final int duration = (toAllApps ?
+ res.getInteger(R.integer.config_appsCustomizeZoomInTime) :
+ res.getInteger(R.integer.config_customizeZoomInTime));
+ final int fadeDuration = (toAllApps ?
+ res.getInteger(R.integer.config_appsCustomizeFadeInTime) :
+ res.getInteger(R.integer.config_customizeFadeInTime));
final float scale = toAllApps ?
- (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) :
+ (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor) :
(float) res.getInteger(R.integer.config_customizeZoomScaleFactor);
- final View toView = toAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+ View tmpView;
+ if (toAllApps) {
+ tmpView = (LauncherApplication.isScreenLarge())
+ ? (View) mAllAppsGrid : mAppsCustomizeTabHost;
+ } else {
+ tmpView = mHomeCustomizationDrawer;
+ }
+ final View toView = tmpView;
setPivotsForZoom(toView, toState, scale);
if (toAllApps) {
- mWorkspace.shrink(ShrinkState.BOTTOM_HIDDEN, animated);
+ if (!springLoaded) {
+ mWorkspace.shrink(ShrinkState.BOTTOM_HIDDEN, animated);
+
+ if (LauncherApplication.isScreenLarge()) {
+ // Everytime we launch into AllApps, we reset the successful drop flag which
+ // controls when it should hide/show the mini workspaces
+ mAllAppsPagedView.resetSuccessfulDropFlag();
+ }
+ } else {
+ mWorkspace.shrink(ShrinkState.BOTTOM_VISIBLE, animated);
+ }
} else {
mWorkspace.shrink(ShrinkState.TOP, animated);
}
@@ -2713,10 +2679,8 @@
if (animated) {
final ValueAnimator scaleAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
scaleAnim.setInterpolator(new Workspace.ZoomOutInterpolator());
- scaleAnim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float b = (Float) animation.getAnimatedValue();
- final float a = 1f - b;
+ scaleAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+ public void onAnimationUpdate(float a, float b) {
((View) toView.getParent()).fastInvalidate();
toView.setFastScaleX(a * scale + b * 1f);
toView.setFastScaleY(a * scale + b * 1f);
@@ -2724,13 +2688,12 @@
});
if (toAllApps) {
+ toView.setVisibility(View.VISIBLE);
toView.setFastAlpha(0f);
ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(fadeDuration);
alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
- alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float b = (Float) animation.getAnimatedValue();
- final float a = 1f - b;
+ alphaAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+ public void onAnimationUpdate(float a, float b) {
// don't need to invalidate because we do so above
toView.setFastAlpha(a * 0f + b * 1f);
}
@@ -2748,6 +2711,7 @@
toView.setTranslationX(0.0f);
toView.setTranslationY(0.0f);
toView.setVisibility(View.VISIBLE);
+ toView.bringToFront();
if (!toAllApps) {
toView.setFastAlpha(1.0f);
}
@@ -2787,6 +2751,7 @@
toView.setScaleX(1.0f);
toView.setScaleY(1.0f);
toView.setVisibility(View.VISIBLE);
+ toView.bringToFront();
if (toView instanceof LauncherTransitionable) {
((LauncherTransitionable) toView).onLauncherTransitionStart(null);
((LauncherTransitionable) toView).onLauncherTransitionEnd(null);
@@ -2801,33 +2766,38 @@
* @param fromState The current state (must be ALL_APPS or CUSTOMIZE).
* @param animated If true, the transition will be animated.
*/
- private void cameraZoomIn(State fromState, boolean animated) {
- cameraZoomIn(fromState, animated, false);
- }
-
private void cameraZoomIn(State fromState, boolean animated, boolean springLoaded) {
Resources res = getResources();
- final boolean fromAllApps = (fromState == State.ALL_APPS);
+ final boolean fromAllApps = (fromState == State.ALL_APPS)
+ || (fromState == State.APPS_CUSTOMIZE);
int duration = fromAllApps ?
- res.getInteger(R.integer.config_allAppsZoomOutTime) :
+ res.getInteger(R.integer.config_appsCustomizeZoomOutTime) :
res.getInteger(R.integer.config_customizeZoomOutTime);
final float scaleFactor = fromAllApps ?
- (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) :
+ (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor) :
(float) res.getInteger(R.integer.config_customizeZoomScaleFactor);
- final View fromView = fromAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+ View tmpView;
+ if (fromAllApps) {
+ tmpView = (LauncherApplication.isScreenLarge())
+ ? (View) mAllAppsGrid : mAppsCustomizeTabHost;
+ } else {
+ tmpView = mHomeCustomizationDrawer;
+ }
+ final View fromView = tmpView;
- mCustomizePagedView.endChoiceMode();
- mAllAppsPagedView.endChoiceMode();
+ if (LauncherApplication.isScreenLarge()) {
+ mCustomizePagedView.endChoiceMode();
+ mAllAppsPagedView.endChoiceMode();
+ }
setPivotsForZoom(fromView, fromState, scaleFactor);
if (!springLoaded) {
mWorkspace.unshrink(animated);
}
-
if (animated) {
if (mStateAnimation != null) mStateAnimation.cancel();
mStateAnimation = new AnimatorSet();
@@ -2837,22 +2807,18 @@
ValueAnimator scaleAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
scaleAnim.setInterpolator(new Workspace.ZoomInInterpolator());
- scaleAnim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float b = (Float) animation.getAnimatedValue();
- final float a = 1f - b;
+ scaleAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+ public void onAnimationUpdate(float a, float b) {
((View)fromView.getParent()).fastInvalidate();
fromView.setFastScaleX(a * oldScaleX + b * scaleFactor);
fromView.setFastScaleY(a * oldScaleY + b * scaleFactor);
}
});
final ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f);
- alphaAnim.setDuration(res.getInteger(R.integer.config_allAppsFadeOutTime));
+ alphaAnim.setDuration(res.getInteger(R.integer.config_appsCustomizeFadeOutTime));
alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
- alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float b = (Float) animation.getAnimatedValue();
- final float a = 1f - b;
+ alphaAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+ public void onAnimationUpdate(float a, float b) {
// don't need to invalidate because we do so above
fromView.setFastAlpha(a * 1f + b * 0f);
}
@@ -2895,34 +2861,6 @@
}
}
- void showAllApps(boolean animated) {
- if (mState != State.WORKSPACE) {
- return;
- }
-
- if (LauncherApplication.isScreenXLarge()) {
- cameraZoomOut(State.ALL_APPS, animated);
- } else {
- mAllAppsGrid.zoom(1.0f, animated);
- }
-
- ((View) mAllAppsGrid).setFocusable(true);
- ((View) mAllAppsGrid).requestFocus();
-
- // TODO: fade these two too
- mDeleteZone.setVisibility(View.GONE);
-
- // Change the state *after* we've called all the transition code
- mState = State.ALL_APPS;
-
- // Pause the auto-advance of widgets until we are out of AllApps
- mUserPresent = false;
- updateRunning();
-
- // send an accessibility event to announce the context change
- getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- }
-
void showWorkspace(boolean animated) {
showWorkspace(animated, null);
}
@@ -2935,7 +2873,7 @@
} else {
mWorkspace.unshrink(animated);
}
- if (mState == State.ALL_APPS) {
+ if (mState == State.ALL_APPS || mState == State.APPS_CUSTOMIZE) {
closeAllApps(animated);
} else if (mState == State.CUSTOMIZE) {
hideCustomizationDrawer(animated);
@@ -2954,12 +2892,16 @@
void enterSpringLoadedDragMode(CellLayout layout) {
mWorkspace.enterSpringLoadedDragMode(layout);
- if (mState == State.ALL_APPS) {
- cameraZoomIn(State.ALL_APPS, true, true);
+ if (mState == State.ALL_APPS || mState == State.APPS_CUSTOMIZE) {
mState = State.ALL_APPS_SPRING_LOADED;
+ if (LauncherApplication.isScreenLarge()) {
+ cameraZoomIn(State.ALL_APPS, true, true);
+ } else {
+ cameraZoomIn(State.APPS_CUSTOMIZE, true, true);
+ }
} else if (mState == State.CUSTOMIZE) {
- cameraZoomIn(State.CUSTOMIZE, true, true);
mState = State.CUSTOMIZE_SPRING_LOADED;
+ cameraZoomIn(State.CUSTOMIZE, true, true);
}/* else {
// we're already in spring loaded mode; don't do anything
}*/
@@ -2968,17 +2910,50 @@
void exitSpringLoadedDragMode() {
if (mState == State.ALL_APPS_SPRING_LOADED) {
mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.BOTTOM_VISIBLE);
- cameraZoomOut(State.ALL_APPS, true);
- mState = State.ALL_APPS;
+ if (LauncherApplication.isScreenLarge()) {
+ cameraZoomOut(State.ALL_APPS, true, true);
+ mState = State.ALL_APPS;
+ } else {
+ cameraZoomOut(State.APPS_CUSTOMIZE, true, true);
+ mState = State.APPS_CUSTOMIZE;
+ }
} else if (mState == State.CUSTOMIZE_SPRING_LOADED) {
mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.TOP);
- cameraZoomOut(State.CUSTOMIZE, true);
+ cameraZoomOut(State.CUSTOMIZE, true, true);
mState = State.CUSTOMIZE;
}/* else {
// we're not in spring loaded mode; don't do anything
}*/
}
+ void showAllApps(boolean animated) {
+ if (mState != State.WORKSPACE) return;
+ if (LauncherApplication.isScreenLarge()) {
+ cameraZoomOut(State.ALL_APPS, animated, false);
+ ((View) mAllAppsGrid).requestFocus();
+
+ // TODO: fade these two too
+ mDeleteZone.setVisibility(View.GONE);
+
+ // Change the state *after* we've called all the transition code
+ mState = State.ALL_APPS;
+ } else {
+ View appsCustomizePane = findViewById(R.id.apps_customize_pane);
+ cameraZoomOut(State.APPS_CUSTOMIZE, animated, false);
+ appsCustomizePane.requestFocus();
+
+ // Change the state *after* we've called all the transition code
+ mState = State.APPS_CUSTOMIZE;
+ }
+
+ // Pause the auto-advance of widgets until we are out of AllApps
+ mUserPresent = false;
+ updateRunning();
+
+ // Send an accessibility event to announce the context change
+ getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ }
+
/**
* Things to test when changing this code.
* - Home from workspace
@@ -3019,15 +2994,22 @@
* - From another workspace
*/
void closeAllApps(boolean animated) {
- if (mState == State.ALL_APPS || mState == State.ALL_APPS_SPRING_LOADED) {
- mWorkspace.setVisibility(View.VISIBLE);
- if (LauncherApplication.isScreenXLarge()) {
- cameraZoomIn(State.ALL_APPS, animated);
- } else {
- mAllAppsGrid.zoom(0.0f, animated);
+ if (LauncherApplication.isScreenLarge()) {
+ if (mState == State.ALL_APPS || mState == State.ALL_APPS_SPRING_LOADED) {
+ mWorkspace.setVisibility(View.VISIBLE);
+ cameraZoomIn(State.ALL_APPS, animated, false);
+
+ // Set focus to the AllApps button
+ findViewById(R.id.all_apps_button).requestFocus();
}
- ((View)mAllAppsGrid).setFocusable(false);
- mWorkspace.getChildAt(mWorkspace.getCurrentPage()).requestFocus();
+ } else {
+ if (mState == State.APPS_CUSTOMIZE || mState == State.ALL_APPS_SPRING_LOADED) {
+ mWorkspace.setVisibility(View.VISIBLE);
+ cameraZoomIn(State.APPS_CUSTOMIZE, animated, false);
+
+ // Set focus to the AllApps button
+ findViewById(R.id.all_apps_button).requestFocus();
+ }
}
}
@@ -3045,7 +3027,7 @@
return;
}
- cameraZoomOut(State.CUSTOMIZE, animated);
+ cameraZoomOut(State.CUSTOMIZE, animated, false);
// Change the state *after* we've called all the transition code
mState = State.CUSTOMIZE;
@@ -3058,7 +3040,10 @@
// Hide the customization drawer (only exists in x-large configuration)
void hideCustomizationDrawer(boolean animated) {
if (mState == State.CUSTOMIZE || mState == State.CUSTOMIZE_SPRING_LOADED) {
- cameraZoomIn(State.CUSTOMIZE, animated);
+ cameraZoomIn(State.CUSTOMIZE, animated, false);
+
+ // Set focus to the customize button
+ findViewById(R.id.configure_button).requestFocus();
}
}
@@ -3140,15 +3125,21 @@
}
private void updateGlobalSearchIcon() {
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
+ final View searchButton = findViewById(R.id.search_button);
+ final View searchDivider = findViewById(R.id.search_divider);
+
final SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
ComponentName activityName = searchManager.getGlobalSearchActivity();
if (activityName != null) {
sGlobalSearchIcon = updateButtonWithIconFromExternalActivity(
R.id.search_button, activityName, R.drawable.ic_generic_search);
+ searchButton.setVisibility(View.VISIBLE);
+ searchDivider.setVisibility(View.VISIBLE);
} else {
- findViewById(R.id.search_button).setVisibility(View.GONE);
+ searchButton.setVisibility(View.GONE);
+ searchDivider.setVisibility(View.GONE);
}
}
}
@@ -3158,14 +3149,20 @@
}
private void updateVoiceSearchIcon() {
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
+ final View searchDivider = findViewById(R.id.search_divider);
+ final View voiceButton = findViewById(R.id.voice_button);
+
Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
ComponentName activityName = intent.resolveActivity(getPackageManager());
if (activityName != null) {
sVoiceSearchIcon = updateButtonWithIconFromExternalActivity(
R.id.voice_button, activityName, R.drawable.ic_voice_search);
+ searchDivider.setVisibility(View.VISIBLE);
+ voiceButton.setVisibility(View.VISIBLE);
} else {
- findViewById(R.id.voice_button).setVisibility(View.GONE);
+ searchDivider.setVisibility(View.GONE);
+ voiceButton.setVisibility(View.GONE);
}
}
}
@@ -3178,16 +3175,21 @@
* Sets the app market icon (shown when all apps is visible on x-large screens)
*/
private void updateAppMarketIcon() {
- if (LauncherApplication.isScreenXLarge()) {
- Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_MARKET);
- // Find the app market activity by resolving an intent.
- // (If multiple app markets are installed, it will return the ResolverActivity.)
- ComponentName activityName = intent.resolveActivity(getPackageManager());
- if (activityName != null) {
- mAppMarketIntent = intent;
- sAppMarketIcon = updateTextButtonWithIconFromExternalActivity(
- R.id.market_button, activityName, R.drawable.app_market_generic);
- }
+ final View marketButton = findViewById(R.id.market_button);
+ Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_MARKET);
+ // Find the app market activity by resolving an intent.
+ // (If multiple app markets are installed, it will return the ResolverActivity.)
+ ComponentName activityName = intent.resolveActivity(getPackageManager());
+ if (activityName != null) {
+ mAppMarketIntent = intent;
+ sAppMarketIcon = updateTextButtonWithIconFromExternalActivity(
+ R.id.market_button, activityName, R.drawable.app_market_generic);
+ marketButton.setVisibility(View.VISIBLE);
+ } else {
+ // We should hide and disable the view so that we don't try and restore the visibility
+ // of it when we swap between drag & normal states from IconDropTarget subclasses.
+ marketButton.setVisibility(View.GONE);
+ marketButton.setEnabled(false);
}
}
@@ -3261,31 +3263,6 @@
break;
}
- case AddAdapter.ITEM_LIVE_FOLDER: {
- // Insert extra item to handle inserting folder
- Bundle bundle = new Bundle();
-
- ArrayList<String> shortcutNames = new ArrayList<String>();
- shortcutNames.add(res.getString(R.string.group_folder));
- bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
-
- ArrayList<ShortcutIconResource> shortcutIcons =
- new ArrayList<ShortcutIconResource>();
- shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
- R.drawable.ic_launcher_folder));
- bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
-
- Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
- pickIntent.putExtra(Intent.EXTRA_INTENT,
- new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER));
- pickIntent.putExtra(Intent.EXTRA_TITLE,
- getText(R.string.title_select_live_folder));
- pickIntent.putExtras(bundle);
-
- startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER);
- break;
- }
-
case AddAdapter.ITEM_WALLPAPER: {
startWallpaper();
break;
@@ -3376,6 +3353,8 @@
*/
public void startBinding() {
final Workspace workspace = mWorkspace;
+
+ mWorkspace.clearDropTargets();
int count = workspace.getChildCount();
for (int i = 0; i < count; i++) {
// Use removeAllViewsInLayout() to avoid an extra requestLayout() and invalidate().
@@ -3421,21 +3400,13 @@
workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1,
false);
break;
- case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
(ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
- (UserFolderInfo) item, mIconCache);
+ (FolderInfo) item, mIconCache);
workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1,
false);
break;
- case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
- final FolderIcon newLiveFolder = LiveFolderIcon.fromXml(
- R.layout.live_folder_icon, this,
- (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
- (LiveFolderInfo) item);
- workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1,
- false);
- break;
}
}
@@ -3504,12 +3475,14 @@
mWorkspace.getChildAt(mWorkspace.getCurrentPage()).requestFocus();
}
- final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS);
- if (userFolders != null) {
- for (long folderId : userFolders) {
+ final long[] folders = mSavedState.getLongArray(RUNTIME_STATE_FOLDERS);
+ if (folders != null) {
+ for (long folderId : folders) {
final FolderInfo info = sFolders.get(folderId);
- if (info != null) {
- openFolder(info);
+ final FolderIcon folderIcon = (FolderIcon)
+ mWorkspace.getViewForTag(info);
+ if (folderIcon != null) {
+ openFolder(folderIcon);
}
}
final Folder openFolder = mWorkspace.getOpenFolder();
@@ -3528,7 +3501,7 @@
// Workaround a bug that occurs when rotating the device while the customization mode is
// open, we trigger a new layout on all the CellLayout children.
- if (LauncherApplication.isScreenXLarge() && (mState == State.CUSTOMIZE)) {
+ if (LauncherApplication.isScreenLarge() && (mState == State.CUSTOMIZE)) {
final int childCount = mWorkspace.getChildCount();
for (int i = 0; i < childCount; ++i) {
mWorkspace.getChildAt(i).requestLayout();
@@ -3561,7 +3534,12 @@
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindAllApplications(ArrayList<ApplicationInfo> apps) {
- mAllAppsGrid.setApps(apps);
+ if (mAllAppsGrid != null) {
+ mAllAppsGrid.setApps(apps);
+ }
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.setApps(apps);
+ }
if (mCustomizePagedView != null) {
mCustomizePagedView.setApps(apps);
}
@@ -3576,7 +3554,12 @@
public void bindAppsAdded(ArrayList<ApplicationInfo> apps) {
setLoadOnResume();
removeDialog(DIALOG_CREATE_SHORTCUT);
- mAllAppsGrid.addApps(apps);
+ if (mAllAppsGrid != null) {
+ mAllAppsGrid.addApps(apps);
+ }
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.addApps(apps);
+ }
if (mCustomizePagedView != null) {
mCustomizePagedView.addApps(apps);
}
@@ -3597,6 +3580,9 @@
if (mAllAppsGrid != null) {
mAllAppsGrid.updateApps(apps);
}
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.updateApps(apps);
+ }
if (mCustomizePagedView != null) {
mCustomizePagedView.updateApps(apps);
}
@@ -3613,7 +3599,12 @@
if (permanent) {
mWorkspace.removeItems(apps);
}
- mAllAppsGrid.removeApps(apps);
+ if (mAllAppsGrid != null) {
+ mAllAppsGrid.removeApps(apps);
+ }
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.removeApps(apps);
+ }
if (mCustomizePagedView != null) {
mCustomizePagedView.removeApps(apps);
}
@@ -3628,6 +3619,9 @@
if (mCustomizePagedView != null) {
mCustomizePagedView.update();
}
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.onPackagesUpdated();
+ }
}
private int mapConfigurationOriActivityInfoOri(int configOri) {
@@ -3686,7 +3680,12 @@
Log.d(TAG, "mDesktopItems.size=" + mDesktopItems.size());
Log.d(TAG, "sFolders.size=" + sFolders.size());
mModel.dumpState();
- mAllAppsGrid.dumpState();
+ if (mAllAppsGrid != null) {
+ mAllAppsGrid.dumpState();
+ }
+ if (mAppsCustomizeContent != null) {
+ mAppsCustomizeContent.dumpState();
+ }
Log.d(TAG, "END launcher2 dump state");
}
}
diff --git a/src/com/android/launcher2/LauncherAnimatorUpdateListener.java b/src/com/android/launcher2/LauncherAnimatorUpdateListener.java
new file mode 100644
index 0000000..dd82113
--- /dev/null
+++ b/src/com/android/launcher2/LauncherAnimatorUpdateListener.java
@@ -0,0 +1,30 @@
+/*
+ * 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.launcher2;
+
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+
+abstract class LauncherAnimatorUpdateListener implements AnimatorUpdateListener {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float b = (Float) animation.getAnimatedValue();
+ final float a = 1f - b;
+ onAnimationUpdate(a, b);
+ }
+
+ abstract void onAnimationUpdate(float a, float b);
+}
\ No newline at end of file
diff --git a/src/com/android/launcher2/LauncherAppWidgetHostView.java b/src/com/android/launcher2/LauncherAppWidgetHostView.java
index 7f60cac..0dd1d83 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHostView.java
@@ -22,6 +22,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewGroup;
import com.android.launcher.R;
@@ -122,4 +123,9 @@
}
super.onVisibilityChanged(changedView, visibility);
}
+
+ @Override
+ public int getDescendantFocusability() {
+ return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+ }
}
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index 8b32f47..67573e0 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -23,24 +23,21 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.os.Handler;
-import dalvik.system.VMRuntime;
public class LauncherApplication extends Application {
public LauncherModel mModel;
public IconCache mIconCache;
- private static boolean sIsScreenXLarge;
+ private static boolean sIsScreenLarge;
private static float sScreenDensity;
private static final boolean ENABLE_ROTATION = false;
@Override
public void onCreate() {
- VMRuntime.getRuntime().setMinimumHeapSize(4 * 1024 * 1024);
-
super.onCreate();
// set sIsScreenXLarge and sScreenDensity *before* creating icon cache
final int screenSize = getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
- sIsScreenXLarge = screenSize == Configuration.SCREENLAYOUT_SIZE_LARGE ||
+ sIsScreenLarge = screenSize == Configuration.SCREENLAYOUT_SIZE_LARGE ||
screenSize == Configuration.SCREENLAYOUT_SIZE_XLARGE;
sScreenDensity = getResources().getDisplayMetrics().density;
@@ -102,11 +99,11 @@
}
public static boolean isInPlaceRotationEnabled() {
- return sIsScreenXLarge && ENABLE_ROTATION;
+ return sIsScreenLarge && ENABLE_ROTATION;
}
- public static boolean isScreenXLarge() {
- return sIsScreenXLarge;
+ public static boolean isScreenLarge() {
+ return sIsScreenLarge;
}
public static float getScreenDensity() {
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index c098749..d5505c5 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -37,7 +37,6 @@
import android.content.Intent.ShortcutIconResource;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
@@ -91,9 +90,6 @@
private AllAppsList mAllAppsList; // only access in worker thread
private IconCache mIconCache;
- final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
- final ArrayList<LauncherAppWidgetInfo> mAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
- final HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>();
private Bitmap mDefaultIcon;
@@ -271,8 +267,7 @@
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
"_id=? and (itemType=? or itemType=?)",
new String[] { String.valueOf(id),
- String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER),
- String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null);
+ String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);
try {
if (c.moveToFirst()) {
@@ -285,11 +280,8 @@
FolderInfo folderInfo = null;
switch (c.getInt(itemTypeIndex)) {
- case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
- folderInfo = findOrMakeUserFolder(folderList, id);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
- folderInfo = findOrMakeLiveFolder(folderList, id);
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ folderInfo = findOrMakeFolder(folderList, id);
break;
}
@@ -391,7 +383,7 @@
/**
* Remove the contents of the specified folder from the database
*/
- static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) {
+ static void deleteFolderContentsFromDatabase(Context context, FolderInfo info) {
final ContentResolver cr = context.getContentResolver();
cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
@@ -522,9 +514,6 @@
mLoaderTask.stopLocked();
}
}
- mItems.clear();
- mAppWidgets.clear();
- mFolders.clear();
}
/**
@@ -540,6 +529,10 @@
private boolean mStopped;
private boolean mLoadAndBindStepFinished;
+ final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
+ final ArrayList<LauncherAppWidgetInfo> mAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
+ final HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>();
+
LoaderTask(Context context, boolean isLaunching) {
mContext = context;
mIsLaunching = isLaunching;
@@ -659,22 +652,6 @@
mLoaderTask = null;
}
}
-
- // Trigger a gc to try to clean up after the stuff is done, since the
- // renderscript allocations aren't charged to the java heap.
- if (mStopped) {
- mHandler.post(new Runnable() {
- public void run() {
- System.gc();
- }
- });
- } else {
- mHandler.postIdle(new Runnable() {
- public void run() {
- System.gc();
- }
- });
- }
}
public void stopLocked() {
@@ -843,8 +820,8 @@
break;
default:
// Item is in a user folder
- UserFolderInfo folderInfo =
- findOrMakeUserFolder(mFolders, container);
+ FolderInfo folderInfo =
+ findOrMakeFolder(mFolders, container);
folderInfo.add(info);
break;
}
@@ -864,9 +841,9 @@
}
break;
- case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
id = c.getLong(idIndex);
- UserFolderInfo folderInfo = findOrMakeUserFolder(mFolders, id);
+ FolderInfo folderInfo = findOrMakeFolder(mFolders, id);
folderInfo.title = c.getString(titleIndex);
folderInfo.id = id;
@@ -889,57 +866,6 @@
mFolders.put(folderInfo.id, folderInfo);
break;
- case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
- id = c.getLong(idIndex);
- Uri uri = Uri.parse(c.getString(uriIndex));
-
- // Make sure the live folder exists
- final ProviderInfo providerInfo =
- context.getPackageManager().resolveContentProvider(
- uri.getAuthority(), 0);
-
- if (providerInfo == null && !isSafeMode) {
- itemsToRemove.add(id);
- } else {
- LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(mFolders, id);
- intentDescription = c.getString(intentIndex);
- intent = null;
- if (intentDescription != null) {
- try {
- intent = Intent.parseUri(intentDescription, 0);
- } catch (URISyntaxException e) {
- // Ignore, a live folder might not have a base intent
- }
- }
-
- liveFolderInfo.title = c.getString(titleIndex);
- liveFolderInfo.id = id;
- liveFolderInfo.uri = uri;
- container = c.getInt(containerIndex);
- liveFolderInfo.container = container;
- liveFolderInfo.screen = c.getInt(screenIndex);
- liveFolderInfo.cellX = c.getInt(cellXIndex);
- liveFolderInfo.cellY = c.getInt(cellYIndex);
- liveFolderInfo.baseIntent = intent;
- liveFolderInfo.displayMode = c.getInt(displayModeIndex);
-
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, liveFolderInfo)) {
- break;
- }
-
- loadLiveFolderIcon(context, c, iconTypeIndex, iconPackageIndex,
- iconResourceIndex, liveFolderInfo);
-
- switch (container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP:
- mItems.add(liveFolderInfo);
- break;
- }
- mFolders.put(liveFolderInfo.id, liveFolderInfo);
- }
- break;
-
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
// Read all Launcher-specific widget details
int appWidgetId = c.getInt(appWidgetIdIndex);
@@ -1294,6 +1220,7 @@
Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
+ Log.d(TAG, "mItems size=" + mItems.size());
}
}
@@ -1623,13 +1550,11 @@
Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
Bitmap icon = null;
- boolean filtered = false;
boolean customIcon = false;
ShortcutIconResource iconResource = null;
if (bitmap != null && bitmap instanceof Bitmap) {
icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);
- filtered = true;
customIcon = true;
} else {
Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
@@ -1668,38 +1593,6 @@
return info;
}
- private void loadLiveFolderIcon(Context context, Cursor c, int iconTypeIndex,
- int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
-
- int iconType = c.getInt(iconTypeIndex);
- switch (iconType) {
- case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
- String packageName = c.getString(iconPackageIndex);
- String resourceName = c.getString(iconResourceIndex);
- PackageManager packageManager = context.getPackageManager();
- try {
- Resources appResources = packageManager.getResourcesForApplication(packageName);
- final int id = appResources.getIdentifier(resourceName, null, null);
- liveFolderInfo.icon = Utilities.createIconBitmap(
- mIconCache.getFullResIcon(appResources, id), context);
- } catch (Exception e) {
- Resources resources = context.getResources();
- liveFolderInfo.icon = Utilities.createIconBitmap(
- mIconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder),
- context);
- }
- liveFolderInfo.iconResource = new Intent.ShortcutIconResource();
- liveFolderInfo.iconResource.packageName = packageName;
- liveFolderInfo.iconResource.resourceName = resourceName;
- break;
- default:
- Resources resources = context.getResources();
- liveFolderInfo.icon = Utilities.createIconBitmap(
- mIconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder),
- context);
- }
- }
-
void updateSavedIcon(Context context, ShortcutInfo info, Cursor c, int iconIndex) {
// If apps can't be on SD, don't even bother.
if (!mAppsCanBeOnExternalStorage) {
@@ -1735,44 +1628,18 @@
}
/**
- * Return an existing UserFolderInfo object if we have encountered this ID previously,
+ * Return an existing FolderInfo object if we have encountered this ID previously,
* or make a new one.
*/
- private static UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) {
+ private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
// See if a placeholder was created for us already
FolderInfo folderInfo = folders.get(id);
- if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) {
+ if (folderInfo == null) {
// No placeholder -- create a new instance
- folderInfo = new UserFolderInfo();
+ folderInfo = new FolderInfo();
folders.put(id, folderInfo);
}
- return (UserFolderInfo) folderInfo;
- }
-
- /**
- * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
- * new one.
- */
- private static LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) {
- // See if a placeholder was created for us already
- FolderInfo folderInfo = folders.get(id);
- if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) {
- // No placeholder -- create a new instance
- folderInfo = new LiveFolderInfo();
- folders.put(id, folderInfo);
- }
- return (LiveFolderInfo) folderInfo;
- }
-
- private static String getLabel(PackageManager manager, ActivityInfo activityInfo) {
- String label = activityInfo.loadLabel(manager).toString();
- if (label == null) {
- label = manager.getApplicationLabel(activityInfo.applicationInfo).toString();
- if (label == null) {
- label = activityInfo.name;
- }
- }
- return label;
+ return folderInfo;
}
private static final Collator sCollator = Collator.getInstance();
@@ -1790,6 +1657,48 @@
return 0;
}
};
+ public static final Comparator<AppWidgetProviderInfo> WIDGET_NAME_COMPARATOR
+ = new Comparator<AppWidgetProviderInfo>() {
+ public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {
+ return sCollator.compare(a.label.toString(), b.label.toString());
+ }
+ };
+ public static class ShortcutNameComparator implements Comparator<ResolveInfo> {
+ private PackageManager mPackageManager;
+ private HashMap<Object, String> mLabelCache;
+ ShortcutNameComparator(PackageManager pm) {
+ mPackageManager = pm;
+ mLabelCache = new HashMap<Object, String>();
+ }
+ public final int compare(ResolveInfo a, ResolveInfo b) {
+ String labelA, labelB;
+ if (mLabelCache.containsKey(a)) labelA = mLabelCache.get(a);
+ else labelA = a.loadLabel(mPackageManager).toString();
+ if (mLabelCache.containsKey(b)) labelB = mLabelCache.get(b);
+ else labelB = b.loadLabel(mPackageManager).toString();
+ return sCollator.compare(labelA, labelB);
+ }
+ };
+ public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
+ private PackageManager mPackageManager;
+ private HashMap<Object, String> mLabelCache;
+ WidgetAndShortcutNameComparator(PackageManager pm) {
+ mPackageManager = pm;
+ mLabelCache = new HashMap<Object, String>();
+ }
+ public final int compare(Object a, Object b) {
+ String labelA, labelB;
+ if (mLabelCache.containsKey(a)) labelA = mLabelCache.get(a);
+ else labelA = (a instanceof AppWidgetProviderInfo) ?
+ ((AppWidgetProviderInfo) a).label :
+ ((ResolveInfo) a).loadLabel(mPackageManager).toString();
+ if (mLabelCache.containsKey(b)) labelB = mLabelCache.get(b);
+ else labelB = (b instanceof AppWidgetProviderInfo) ?
+ ((AppWidgetProviderInfo) b).label :
+ ((ResolveInfo) b).loadLabel(mPackageManager).toString();
+ return sCollator.compare(labelA, labelB);
+ }
+ };
public void dumpState() {
Log.d(TAG, "mCallbacks=" + mCallbacks);
@@ -1797,7 +1706,6 @@
ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mAllAppsList.added);
ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mAllAppsList.removed);
ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mAllAppsList.modified);
- Log.d(TAG, "mItems size=" + mItems.size());
if (mLoaderTask != null) {
mLoaderTask.dumpState();
} else {
diff --git a/src/com/android/launcher2/LauncherSettings.java b/src/com/android/launcher2/LauncherSettings.java
index 9c685ce..c378405 100644
--- a/src/com/android/launcher2/LauncherSettings.java
+++ b/src/com/android/launcher2/LauncherSettings.java
@@ -16,8 +16,8 @@
package com.android.launcher2;
-import android.provider.BaseColumns;
import android.net.Uri;
+import android.provider.BaseColumns;
/**
* Settings related utilities.
@@ -169,11 +169,15 @@
/**
* The favorite is a user created folder
*/
- static final int ITEM_TYPE_USER_FOLDER = 2;
+ static final int ITEM_TYPE_FOLDER = 2;
/**
- * The favorite is a live folder
- */
+ * The favorite is a live folder
+ *
+ * Note: live folders can no longer be added to Launcher, and any live folders which
+ * exist within the launcher database will be ignored when loading. That said, these
+ * entries in the database may still exist, and are not automatically stripped.
+ */
static final int ITEM_TYPE_LIVE_FOLDER = 3;
/**
diff --git a/src/com/android/launcher2/LiveFolder.java b/src/com/android/launcher2/LiveFolder.java
deleted file mode 100644
index 07a295f..0000000
--- a/src/com/android/launcher2/LiveFolder.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.Intent;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.AdapterView;
-import android.net.Uri;
-import android.provider.LiveFolders;
-import android.os.AsyncTask;
-import android.database.Cursor;
-
-import java.lang.ref.WeakReference;
-
-import com.android.launcher.R;
-
-public class LiveFolder extends Folder {
- private AsyncTask<LiveFolderInfo,Void,Cursor> mLoadingTask;
-
- public LiveFolder(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- static LiveFolder fromXml(Context context, FolderInfo folderInfo) {
- final int layout = isDisplayModeList(folderInfo) ?
- R.layout.live_folder_list : R.layout.live_folder_grid;
- return (LiveFolder) LayoutInflater.from(context).inflate(layout, null);
- }
-
- private static boolean isDisplayModeList(FolderInfo folderInfo) {
- return ((LiveFolderInfo) folderInfo).displayMode ==
- LiveFolders.DISPLAY_MODE_LIST;
- }
-
- @Override
- public void onItemClick(AdapterView parent, View v, int position, long id) {
- LiveFolderAdapter.ViewHolder holder = (LiveFolderAdapter.ViewHolder) v.getTag();
-
- if (holder.useBaseIntent) {
- final Intent baseIntent = ((LiveFolderInfo) mInfo).baseIntent;
- if (baseIntent != null) {
- final Intent intent = new Intent(baseIntent);
- Uri uri = baseIntent.getData();
- uri = uri.buildUpon().appendPath(Long.toString(holder.id)).build();
- intent.setData(uri);
- mLauncher.startActivitySafely(intent, "(position=" + position + ", id=" + id + ")");
- }
- } else if (holder.intent != null) {
- mLauncher.startActivitySafely(holder.intent,
- "(position=" + position + ", id=" + id + ")");
- }
- }
-
- @Override
- public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
- return false;
- }
-
- void bind(FolderInfo info) {
- super.bind(info);
- if (mLoadingTask != null && mLoadingTask.getStatus() == AsyncTask.Status.RUNNING) {
- mLoadingTask.cancel(true);
- }
- mLoadingTask = new FolderLoadingTask(this).execute((LiveFolderInfo) info);
- }
-
- @Override
- void onOpen() {
- super.onOpen();
- requestFocus();
- }
-
- @Override
- void onClose() {
- super.onClose();
- if (mLoadingTask != null && mLoadingTask.getStatus() == AsyncTask.Status.RUNNING) {
- mLoadingTask.cancel(true);
- }
-
- // The adapter can be null if onClose() is called before FolderLoadingTask
- // is done querying the provider
- final LiveFolderAdapter adapter = (LiveFolderAdapter) mContent.getAdapter();
- if (adapter != null) {
- adapter.cleanup();
- }
- }
-
- static class FolderLoadingTask extends AsyncTask<LiveFolderInfo, Void, Cursor> {
- private final WeakReference<LiveFolder> mFolder;
- private LiveFolderInfo mInfo;
-
- FolderLoadingTask(LiveFolder folder) {
- mFolder = new WeakReference<LiveFolder>(folder);
- }
-
- protected Cursor doInBackground(LiveFolderInfo... params) {
- final LiveFolder folder = mFolder.get();
- if (folder != null) {
- mInfo = params[0];
- return LiveFolderAdapter.query(folder.mLauncher, mInfo);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Cursor cursor) {
- if (!isCancelled()) {
- if (cursor != null) {
- final LiveFolder folder = mFolder.get();
- if (folder != null) {
- final Launcher launcher = folder.mLauncher;
- folder.setContentAdapter(new LiveFolderAdapter(launcher, mInfo, cursor));
- }
- }
- } else if (cursor != null) {
- cursor.close();
- }
- }
- }
-}
diff --git a/src/com/android/launcher2/LiveFolderAdapter.java b/src/com/android/launcher2/LiveFolderAdapter.java
deleted file mode 100644
index fb9c6a3..0000000
--- a/src/com/android/launcher2/LiveFolderAdapter.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.widget.CursorAdapter;
-import android.widget.TextView;
-import android.widget.ImageView;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.content.pm.PackageManager;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.database.Cursor;
-import android.provider.LiveFolders;
-import android.graphics.drawable.Drawable;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.lang.ref.SoftReference;
-
-import com.android.launcher.R;
-
-class LiveFolderAdapter extends CursorAdapter {
- private boolean mIsList;
- private LayoutInflater mInflater;
-
- private final HashMap<String, Drawable> mIcons = new HashMap<String, Drawable>();
- private final HashMap<Long, SoftReference<Drawable>> mCustomIcons =
- new HashMap<Long, SoftReference<Drawable>>();
- private final Launcher mLauncher;
-
- LiveFolderAdapter(Launcher launcher, LiveFolderInfo info, Cursor cursor) {
- super(launcher, cursor, true);
- mIsList = info.displayMode == LiveFolders.DISPLAY_MODE_LIST;
- mInflater = LayoutInflater.from(launcher);
- mLauncher = launcher;
-
- mLauncher.startManagingCursor(getCursor());
- }
-
- static Cursor query(Context context, LiveFolderInfo info) {
- return context.getContentResolver().query(info.uri, null, null,
- null, LiveFolders.NAME + " ASC");
- }
-
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- View view;
- final ViewHolder holder = new ViewHolder();
-
- if (!mIsList) {
- view = mInflater.inflate(R.layout.application_boxed, parent, false);
- } else {
- view = mInflater.inflate(R.layout.application_list, parent, false);
- holder.description = (TextView) view.findViewById(R.id.description);
- holder.icon = (ImageView) view.findViewById(R.id.icon);
- }
-
- holder.name = (TextView) view.findViewById(R.id.name);
-
- holder.idIndex = cursor.getColumnIndexOrThrow(LiveFolders._ID);
- holder.nameIndex = cursor.getColumnIndexOrThrow(LiveFolders.NAME);
- holder.descriptionIndex = cursor.getColumnIndex(LiveFolders.DESCRIPTION);
- holder.intentIndex = cursor.getColumnIndex(LiveFolders.INTENT);
- holder.iconBitmapIndex = cursor.getColumnIndex(LiveFolders.ICON_BITMAP);
- holder.iconResourceIndex = cursor.getColumnIndex(LiveFolders.ICON_RESOURCE);
- holder.iconPackageIndex = cursor.getColumnIndex(LiveFolders.ICON_PACKAGE);
-
- view.setTag(holder);
-
- return view;
- }
-
- public void bindView(View view, Context context, Cursor cursor) {
- final ViewHolder holder = (ViewHolder) view.getTag();
-
- holder.id = cursor.getLong(holder.idIndex);
- final Drawable icon = loadIcon(context, cursor, holder);
-
- holder.name.setText(cursor.getString(holder.nameIndex));
-
- if (!mIsList) {
- holder.name.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null);
- } else {
- final boolean hasIcon = icon != null;
- holder.icon.setVisibility(hasIcon ? View.VISIBLE : View.GONE);
- if (hasIcon) holder.icon.setImageDrawable(icon);
-
- if (holder.descriptionIndex != -1) {
- final String description = cursor.getString(holder.descriptionIndex);
- if (description != null) {
- holder.description.setText(description);
- holder.description.setVisibility(View.VISIBLE);
- } else {
- holder.description.setVisibility(View.GONE);
- }
- } else {
- holder.description.setVisibility(View.GONE);
- }
- }
-
- if (holder.intentIndex != -1) {
- try {
- holder.intent = Intent.parseUri(cursor.getString(holder.intentIndex), 0);
- } catch (URISyntaxException e) {
- // Ignore
- }
- } else {
- holder.useBaseIntent = true;
- }
- }
-
- private Drawable loadIcon(Context context, Cursor cursor, ViewHolder holder) {
- Drawable icon = null;
- byte[] data = null;
-
- if (holder.iconBitmapIndex != -1) {
- data = cursor.getBlob(holder.iconBitmapIndex);
- }
-
- if (data != null) {
- final SoftReference<Drawable> reference = mCustomIcons.get(holder.id);
- if (reference != null) {
- icon = reference.get();
- }
-
- if (icon == null) {
- final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- final Bitmap resampled = Utilities.resampleIconBitmap(bitmap, mContext);
- if (bitmap != resampled) {
- // If we got back a different object, we don't need the old one any more.
- bitmap.recycle();
- }
- icon = new FastBitmapDrawable(resampled);
- mCustomIcons.put(holder.id, new SoftReference<Drawable>(icon));
- }
- } else if (holder.iconResourceIndex != -1 && holder.iconPackageIndex != -1) {
- final String resource = cursor.getString(holder.iconResourceIndex);
- icon = mIcons.get(resource);
- if (icon == null) {
- try {
- final PackageManager packageManager = context.getPackageManager();
- Resources resources = packageManager.getResourcesForApplication(
- cursor.getString(holder.iconPackageIndex));
- final int id = resources.getIdentifier(resource,
- null, null);
- icon = new FastBitmapDrawable(
- Utilities.createIconBitmap(resources.getDrawable(id), mContext));
- mIcons.put(resource, icon);
- } catch (Exception e) {
- // Ignore
- }
- }
- }
-
- return icon;
- }
-
- void cleanup() {
- for (Drawable icon : mIcons.values()) {
- icon.setCallback(null);
- }
- mIcons.clear();
-
- for (SoftReference<Drawable> icon : mCustomIcons.values()) {
- final Drawable drawable = icon.get();
- if (drawable != null) {
- drawable.setCallback(null);
- }
- }
- mCustomIcons.clear();
-
- final Cursor cursor = getCursor();
- if (cursor != null) {
- try {
- cursor.close();
- } finally {
- mLauncher.stopManagingCursor(cursor);
- }
- }
- }
-
- static class ViewHolder {
- TextView name;
- TextView description;
- ImageView icon;
-
- Intent intent;
- long id;
- boolean useBaseIntent;
-
- int idIndex;
- int nameIndex;
- int descriptionIndex = -1;
- int intentIndex = -1;
- int iconBitmapIndex = -1;
- int iconResourceIndex = -1;
- int iconPackageIndex = -1;
- }
-}
diff --git a/src/com/android/launcher2/LiveFolderIcon.java b/src/com/android/launcher2/LiveFolderIcon.java
deleted file mode 100644
index 5b73a59..0000000
--- a/src/com/android/launcher2/LiveFolderIcon.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.graphics.Bitmap;
-
-import com.android.launcher.R;
-
-public class LiveFolderIcon extends FolderIcon {
- public LiveFolderIcon(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public LiveFolderIcon(Context context) {
- super(context);
- }
-
- static LiveFolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
- LiveFolderInfo folderInfo) {
-
- LiveFolderIcon icon = (LiveFolderIcon)
- LayoutInflater.from(launcher).inflate(resId, group, false);
-
- final Resources resources = launcher.getResources();
- Bitmap b = folderInfo.icon;
- if (b == null) {
- b = Utilities.createIconBitmap(resources.getDrawable(R.drawable.ic_launcher_folder),
- launcher);
- }
- icon.setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(b), null, null);
- icon.setText(folderInfo.title);
- icon.setTag(folderInfo);
- icon.setOnClickListener(launcher);
-
- return icon;
- }
-
- @Override
- public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- return false;
- }
-
- @Override
- public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- }
-
- @Override
- public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- }
-
- @Override
- public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- }
-
- @Override
- public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- }
-}
diff --git a/src/com/android/launcher2/LiveFolderInfo.java b/src/com/android/launcher2/LiveFolderInfo.java
deleted file mode 100644
index 74b0217..0000000
--- a/src/com/android/launcher2/LiveFolderInfo.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.ContentValues;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.net.Uri;
-
-class LiveFolderInfo extends FolderInfo {
-
- /**
- * The base intent, if it exists.
- */
- Intent baseIntent;
-
- /**
- * The live folder's content uri.
- */
- Uri uri;
-
- /**
- * The live folder's display type.
- */
- int displayMode;
-
- /**
- * The live folder icon.
- */
- Bitmap icon;
-
- /**
- * Reference to the live folder icon as an application's resource.
- */
- Intent.ShortcutIconResource iconResource;
-
- LiveFolderInfo() {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER;
- }
-
- @Override
- void onAddToDatabase(ContentValues values) {
- super.onAddToDatabase(values);
- values.put(LauncherSettings.Favorites.TITLE, title.toString());
- values.put(LauncherSettings.Favorites.URI, uri.toString());
- if (baseIntent != null) {
- values.put(LauncherSettings.Favorites.INTENT, baseIntent.toUri(0));
- }
- values.put(LauncherSettings.Favorites.ICON_TYPE, LauncherSettings.Favorites.ICON_TYPE_RESOURCE);
- values.put(LauncherSettings.Favorites.DISPLAY_MODE, displayMode);
- if (iconResource != null) {
- values.put(LauncherSettings.Favorites.ICON_PACKAGE, iconResource.packageName);
- values.put(LauncherSettings.Favorites.ICON_RESOURCE, iconResource.resourceName);
- }
- }
-}
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index a6ae0e1..1180106 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -29,6 +29,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.ActionMode;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -50,6 +51,7 @@
*/
public abstract class PagedView extends ViewGroup {
private static final String TAG = "PagedView";
+ private static final boolean DEBUG = false;
protected static final int INVALID_PAGE = -1;
// the min drag distance for a fling to register, to prevent random page shifts
@@ -292,6 +294,10 @@
mIsPageMoving = false;
}
+ protected boolean isPageMoving() {
+ return mIsPageMoving;
+ }
+
// a method that subclasses can override to add behavior
protected void onPageBeginMoving() {
}
@@ -393,6 +399,7 @@
// The children are given the same width and height as the workspace
// unless they were set to WRAP_CONTENT
+ if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
// disallowing padding in paged view (just pass 0)
@@ -420,6 +427,8 @@
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
+ if (DEBUG) Log.d(TAG, "\tmeasure-child" + i + ": " + child.getMeasuredWidth() + ", "
+ + child.getMeasuredHeight());
}
if (heightMode == MeasureSpec.AT_MOST) {
@@ -474,6 +483,7 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
setHorizontalScrollBarEnabled(false);
int newX = getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage);
@@ -487,6 +497,8 @@
final int childCount = getChildCount();
int childLeft = 0;
if (childCount > 0) {
+ if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getMeasuredWidth() + ", "
+ + getChildWidth(0));
childLeft = getRelativeChildOffset(0);
}
@@ -500,6 +512,7 @@
childTop += ((getMeasuredHeight() - verticalPadding) - childHeight) / 2;
}
+ if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(), childTop + childHeight);
childLeft += childWidth + mPageSpacing;
@@ -518,7 +531,8 @@
protected void updateAdjacentPagesAlpha() {
if (mFadeInAdjacentScreens) {
if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) {
- int halfScreenSize = getMeasuredWidth() / 2;
+ int screenWidth = getMeasuredWidth();
+ int halfScreenSize = screenWidth / 2;
int screenCenter = mScrollX + halfScreenSize;
final int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
@@ -531,7 +545,7 @@
// we should just assume full page width (and calculate the offset according to
// that).
if (childWidth <= 0) {
- childWidth = getMeasuredWidth();
+ childWidth = screenWidth;
childCenter = (i * childWidth) + (childWidth / 2);
}
@@ -989,6 +1003,7 @@
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
if (!mDeferScrollUpdate) {
scrollBy((int) deltaX, 0);
+ if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
} else {
invalidate();
}
@@ -1162,7 +1177,7 @@
public void requestChildFocus(View child, View focused) {
super.requestChildFocus(child, focused);
int page = indexOfChild(child);
- if (page >= 0 && !isInTouchMode()) {
+ if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
snapToPage(page);
}
}
@@ -1184,9 +1199,16 @@
protected void setMinimumWidthOverride(int minimumWidth) {
mMinimumWidth = minimumWidth;
}
+ protected void resetMinimumWidthOverride() {
+ mMinimumWidth = 0;
+ }
protected int getChildWidth(int index) {
- return Math.max(mMinimumWidth, getChildAt(index).getMeasuredWidth());
+ // This functions are called enough times that it actually makes a difference in the
+ // profiler -- so just inline the max() here
+ final int measuredWidth = getChildAt(index).getMeasuredWidth();
+ final int minWidth = mMinimumWidth;
+ return (minWidth > measuredWidth) ? minWidth : measuredWidth;
}
protected int getRelativeChildOffset(int index) {
@@ -1205,7 +1227,12 @@
}
protected int getScaledMeasuredWidth(View child) {
- return (int) (Math.max(mMinimumWidth, child.getMeasuredWidth()) * mLayoutScale + 0.5f);
+ // This functions are called enough times that it actually makes a difference in the
+ // profiler -- so just inline the max() here
+ final int measuredWidth = child.getMeasuredWidth();
+ final int minWidth = mMinimumWidth;
+ final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
+ return (int) (maxWidth * mLayoutScale + 0.5f);
}
int getPageNearestToCenterOfScreen() {
@@ -1255,6 +1282,9 @@
whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
int halfScreenSize = getMeasuredWidth() / 2;
+ if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
+ if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
+ + getMeasuredWidth() + ", " + getChildWidth(whichPage));
final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
int delta = newX - mUnboundedScrollX;
int duration = 0;
@@ -1292,6 +1322,9 @@
protected void snapToPage(int whichPage, int duration) {
whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
+ if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
+ if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getMeasuredWidth() + ", "
+ + getChildWidth(whichPage));
int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
final int sX = mUnboundedScrollX;
final int delta = newX - sX;
@@ -1403,6 +1436,8 @@
if (page < count) {
int lowerPageBound = getAssociatedLowerPageBound(page);
int upperPageBound = getAssociatedUpperPageBound(page);
+ if (DEBUG) Log.d(TAG, "loadAssociatedPages: " + lowerPageBound + "/"
+ + upperPageBound);
for (int i = 0; i < count; ++i) {
Page layout = (Page) getChildAt(i);
final int childCount = layout.getPageChildCount();
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index 762ec58..54bdec4 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -17,12 +17,15 @@
package com.android.launcher2;
import android.content.Context;
+import android.content.res.Resources;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
+import com.android.launcher.R;
+
/**
* An abstraction of the original CellLayout which supports laying out items
* which span multiple cells into a grid-like layout. Also supports dimming
@@ -37,7 +40,6 @@
private int mCellHeight;
private int mWidthGap;
private int mHeightGap;
- private static int sDefaultCellDimensions = 96;
protected PagedViewCellLayoutChildren mChildren;
private PagedViewCellLayoutChildren mHolographicChildren;
private boolean mAllowHardwareLayerCreation = false;
@@ -57,7 +59,9 @@
setAlwaysDrawnWithCacheEnabled(false);
// setup default cell parameters
- mCellWidth = mCellHeight = sDefaultCellDimensions;
+ Resources resources = context.getResources();
+ mCellWidth = resources.getDimensionPixelSize(R.dimen.apps_customize_cell_width);
+ mCellHeight = resources.getDimensionPixelSize(R.dimen.apps_customize_cell_height);
mCellCountX = LauncherModel.getCellCountX();
mCellCountY = LauncherModel.getCellCountY();
mWidthGap = mHeightGap = -1;
@@ -125,7 +129,7 @@
}
public boolean addViewToCellLayout(View child, int index, int childId,
- PagedViewCellLayout.LayoutParams params) {
+ PagedViewCellLayout.LayoutParams params, boolean createHolographicOutlines) {
final PagedViewCellLayout.LayoutParams lp = params;
// Generate an id for each view, this assumes we have at most 256x256 cells
@@ -145,7 +149,10 @@
if (mAllowHardwareLayerCreation) {
pagedViewIcon.disableCache();
}
- mHolographicChildren.addView(pagedViewIcon.getHolographicOutlineView(), index, lp);
+ if (createHolographicOutlines) {
+ mHolographicChildren.addView(pagedViewIcon.getHolographicOutlineView(),
+ index, lp);
+ }
}
return true;
}
@@ -180,6 +187,14 @@
return mChildren.indexOfChild(v);
}
+ public int getCellCountX() {
+ return mCellCountX;
+ }
+
+ public int getCellCountY() {
+ return mCellCountY;
+ }
+
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO: currently ignoring padding
@@ -244,15 +259,23 @@
}
int getContentWidth() {
- // Return the distance from the left edge of the content of the leftmost icon to
- // the right edge of the content of the rightmost icon
+ if (LauncherApplication.isScreenLarge()) {
+ // Return the distance from the left edge of the content of the leftmost icon to
+ // the right edge of the content of the rightmost icon
- // icons are centered within cells, find out how much padding that accounts for
- return getWidthBeforeFirstLayout() - (mCellWidth - Utilities.getIconContentSize());
+ // icons are centered within cells, find out how much padding that accounts for
+ return getWidthBeforeFirstLayout() - (mCellWidth - Utilities.getIconContentSize());
+ } else {
+ return getWidthBeforeFirstLayout() + mPaddingLeft + mPaddingRight;
+ }
+ }
+
+ int getContentHeight() {
+ return mCellCountY * mCellHeight + (mCellCountY - 1) * Math.max(0, mHeightGap);
}
int getWidthBeforeFirstLayout() {
- return mCellCountX * mCellWidth + (mCellCountX - 1) * mWidthGap;
+ return mCellCountX * mCellWidth + (mCellCountX - 1) * Math.max(0, mWidthGap);
}
@Override
@@ -260,7 +283,12 @@
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- child.layout(0, 0, r - l, b - t);
+ if (LauncherApplication.isScreenLarge()) {
+ child.layout(0, 0, r - l, b - t);
+ } else {
+ child.layout(mPaddingLeft, mPaddingTop, getMeasuredWidth() - mPaddingRight,
+ getMeasuredHeight() - mPaddingBottom);
+ }
}
}
@@ -449,8 +477,13 @@
height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
topMargin - bottomMargin;
- x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
- y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+ if (LauncherApplication.isScreenLarge()) {
+ x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
+ y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+ } else {
+ x = myCellX * (cellWidth + widthGap) + leftMargin;
+ y = myCellY * (cellHeight + heightGap) + topMargin;
+ }
}
public Object getTag() {
diff --git a/src/com/android/launcher2/PagedViewExtendedLayout.java b/src/com/android/launcher2/PagedViewExtendedLayout.java
index e54d261..94890d8 100644
--- a/src/com/android/launcher2/PagedViewExtendedLayout.java
+++ b/src/com/android/launcher2/PagedViewExtendedLayout.java
@@ -23,10 +23,11 @@
import android.widget.LinearLayout;
/**
- * The linear layout used strictly for the widget/wallpaper tab of the customization tray
+ * The linear layout used strictly for the widget/wallpaper tab of the customization tray.
+ * To be deprecated.
*/
public class PagedViewExtendedLayout extends LinearLayout implements Page {
- static final String TAG = "PagedViewWidgetLayout";
+ static final String TAG = "PagedViewExtendedLayout";
public PagedViewExtendedLayout(Context context) {
this(context, null);
@@ -40,6 +41,22 @@
super(context, attrs, defStyle);
}
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (LauncherApplication.isScreenLarge()) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ } else {
+ // PagedView currently has issues with different-sized pages since it calculates the
+ // offset of each page to scroll to before it updates the actual size of each page
+ // (which canchange depending on the content if the contains aren't a fixed size).
+ // We work around this by having a minimum size on each widget page).
+ int widthSpecSize = Math.max(getSuggestedMinimumWidth(),
+ MeasureSpec.getSize(widthMeasureSpec));
+ int widthSpecMode = MeasureSpec.AT_MOST;
+ super.onMeasure(MeasureSpec.makeMeasureSpec(widthSpecSize, widthSpecMode),
+ heightMeasureSpec);
+ }
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
// We eat up the touch events here, since the PagedView (which uses the same swiping
@@ -94,4 +111,11 @@
public int indexOfChildOnPage(View v) {
return indexOfChild(v);
}
+
+ public static class LayoutParams extends LinearLayout.LayoutParams {
+ public LayoutParams() {
+ super(LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.MATCH_PARENT);
+ }
+ }
}
diff --git a/src/com/android/launcher2/PagedViewGridLayout.java b/src/com/android/launcher2/PagedViewGridLayout.java
new file mode 100644
index 0000000..cedf71c
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewGridLayout.java
@@ -0,0 +1,120 @@
+/*
+ * 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.launcher2;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+/**
+ * The grid based layout used strictly for the widget/wallpaper tab of the AppsCustomize pane
+ */
+public class PagedViewGridLayout extends FrameLayout implements Page {
+ static final String TAG = "PagedViewGridLayout";
+
+ private int mCellCountX;
+ private int mCellCountY;
+
+ public PagedViewGridLayout(Context context, int cellCountX, int cellCountY) {
+ super(context, null, 0);
+ mCellCountX = cellCountX;
+ mCellCountY = cellCountY;
+ }
+
+ int getCellCountX() {
+ return mCellCountX;
+ }
+ int getCellCountY() {
+ return mCellCountY;
+ }
+
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // PagedView currently has issues with different-sized pages since it calculates the
+ // offset of each page to scroll to before it updates the actual size of each page
+ // (which can change depending on the content if the contents aren't a fixed size).
+ // We work around this by having a minimum size on each widget page).
+ int widthSpecSize = Math.max(getSuggestedMinimumWidth(),
+ MeasureSpec.getSize(widthMeasureSpec));
+ int widthSpecMode = MeasureSpec.AT_MOST;
+ super.onMeasure(MeasureSpec.makeMeasureSpec(widthSpecSize, widthSpecMode),
+ heightMeasureSpec);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ // We eat up the touch events here, since the PagedView (which uses the same swiping
+ // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
+ // the user is scrolling between pages. This means that if the pages themselves don't
+ // handle touch events, it gets forwarded up to PagedView itself, and it's own
+ // onTouchEvent() handling will prevent further intercept touch events from being called
+ // (it's the same view in that case). This is not ideal, but to prevent more changes,
+ // we just always mark the touch event as handled.
+ return super.onTouchEvent(event) || true;
+ }
+
+ @Override
+ protected boolean onSetAlpha(int alpha) {
+ return true;
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ setChildrenAlpha(alpha);
+ super.setAlpha(alpha);
+ }
+
+ private void setChildrenAlpha(float alpha) {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ getChildAt(i).setAlpha(alpha);
+ }
+ }
+
+ @Override
+ public void removeAllViewsOnPage() {
+ removeAllViews();
+ }
+
+ @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/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
index bde6559..e23f1c6 100644
--- a/src/com/android/launcher2/PagedViewIcon.java
+++ b/src/com/android/launcher2/PagedViewIcon.java
@@ -16,9 +16,8 @@
package com.android.launcher2;
-import com.android.launcher.R;
-
import android.animation.ObjectAnimator;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -31,9 +30,11 @@
import android.os.HandlerThread;
import android.os.Message;
import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
import android.widget.Checkable;
-import android.widget.TextView;
+import com.android.launcher.R;
/**
@@ -121,15 +122,15 @@
// Set up fade in/out constants
final Resources r = context.getResources();
- final int alpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha);
+ final int alpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha);
if (alpha > 0) {
- mCheckedAlpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha) / 256.0f;
- mCheckedFadeInDuration = r.getInteger(R.integer.icon_allAppsCustomizeFadeInTime);
- mCheckedFadeOutDuration = r.getInteger(R.integer.icon_allAppsCustomizeFadeOutTime);
+ mCheckedAlpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha) / 256.0f;
+ mCheckedFadeInDuration =
+ r.getInteger(R.integer.config_dragAppsCustomizeIconFadeInDuration);
+ mCheckedFadeOutDuration =
+ r.getInteger(R.integer.config_dragAppsCustomizeIconFadeOutDuration);
}
- setFocusable(true);
- setBackgroundDrawable(null);
mHolographicOutlineView = new HolographicPagedViewIcon(context, this);
}
@@ -171,8 +172,8 @@
public void applyFromResolveInfo(ResolveInfo info, PackageManager packageManager,
PagedViewIconCache cache, IconCache modelIconCache, boolean createHolographicOutlines) {
- mIcon = Utilities.createIconBitmap(
- modelIconCache.getFullResIcon(info, packageManager), mContext);
+ ComponentName cn = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
+ mIcon = modelIconCache.getIcon(cn, info);
setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null);
setText(info.loadLabel(packageManager));
setTag(info);
@@ -217,7 +218,8 @@
// draw any blended overlays
if (mCheckedOutline == null) {
- if (mHolographicOutline != null && mHolographicAlpha > 0) {
+ if (canvas.isHardwareAccelerated() && mHolographicOutline != null
+ && mHolographicAlpha > 0) {
mPaint.setAlpha(mHolographicAlpha);
overlay = mHolographicOutline;
}
@@ -245,6 +247,18 @@
}
@Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return FocusHelper.handlePagedViewIconKeyEvent(this, keyCode, event)
+ || super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return FocusHelper.handlePagedViewIconKeyEvent(this, keyCode, event)
+ || super.onKeyUp(keyCode, event);
+ }
+
+ @Override
public boolean isChecked() {
return mIsChecked;
}
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
index 72f928b..2ffa398 100644
--- a/src/com/android/launcher2/PagedViewWidget.java
+++ b/src/com/android/launcher2/PagedViewWidget.java
@@ -36,6 +36,7 @@
import android.os.HandlerThread;
import android.os.Message;
import android.util.AttributeSet;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Checkable;
@@ -63,6 +64,7 @@
private PagedViewIconCache.Key mIconCacheKey;
private PagedViewIconCache mIconCache;
+ private String mDimensionsFormatString;
private int mAlpha = 255;
private int mHolographicAlpha;
@@ -153,14 +155,16 @@
// Set up fade in/out constants
final Resources r = context.getResources();
- final int alpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha);
+ final int alpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha);
if (alpha > 0) {
- mCheckedAlpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha) / 256.0f;
- mCheckedFadeInDuration = r.getInteger(R.integer.icon_allAppsCustomizeFadeInTime);
- mCheckedFadeOutDuration = r.getInteger(R.integer.icon_allAppsCustomizeFadeOutTime);
+ mCheckedAlpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha) / 256.0f;
+ mCheckedFadeInDuration =
+ r.getInteger(R.integer.config_dragAppsCustomizeIconFadeInDuration);
+ mCheckedFadeOutDuration =
+ r.getInteger(R.integer.config_dragAppsCustomizeIconFadeOutDuration);
}
+ mDimensionsFormatString = r.getString(R.string.widget_dims_format);
- setFocusable(true);
setWillNotDraw(false);
setClipToPadding(false);
}
@@ -178,14 +182,16 @@
FastBitmapDrawable preview, int maxWidth, int[] cellSpan,
PagedViewIconCache cache, boolean createHolographicOutline) {
final ImageView image = (ImageView) findViewById(R.id.widget_preview);
- image.setMaxWidth(maxWidth);
+ if (maxWidth > -1) {
+ image.setMaxWidth(maxWidth);
+ }
image.setImageDrawable(preview);
mPreviewImageView = image;
final TextView name = (TextView) findViewById(R.id.widget_name);
name.setText(info.label);
name.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
final TextView dims = (TextView) findViewById(R.id.widget_dims);
- dims.setText(mContext.getString(R.string.widget_dims_format, cellSpan[0], cellSpan[1]));
+ dims.setText(String.format(mDimensionsFormatString, cellSpan[0], cellSpan[1]));
dims.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
if (createHolographicOutline) {
@@ -196,6 +202,28 @@
}
}
+ public void applyFromResolveInfo(PackageManager pm, ResolveInfo info,
+ FastBitmapDrawable preview, PagedViewIconCache cache, boolean createHolographicOutline){
+ final ImageView image = (ImageView) findViewById(R.id.widget_preview);
+ image.setImageDrawable(preview);
+ mPreviewImageView = image;
+ final TextView name = (TextView) findViewById(R.id.widget_name);
+ name.setText(info.loadLabel(pm));
+ name.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ final TextView dims = (TextView) findViewById(R.id.widget_dims);
+ if (dims != null) {
+ dims.setText(String.format(mDimensionsFormatString, 1, 1));
+ dims.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ }
+
+ if (createHolographicOutline) {
+ mIconCache = cache;
+ mIconCacheKey = new PagedViewIconCache.Key(info);
+ mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
+ mPreview = preview;
+ }
+ }
+
public void applyFromWallpaperInfo(ResolveInfo info, PackageManager packageManager,
FastBitmapDrawable preview, int maxWidth, PagedViewIconCache cache,
boolean createHolographicOutline) {
@@ -228,6 +256,28 @@
}
@Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (LauncherApplication.isScreenLarge()) {
+ return FocusHelper.handlePagedViewWidgetKeyEvent(this, keyCode, event)
+ || super.onKeyDown(keyCode, event);
+ } else {
+ return FocusHelper.handlePagedViewGridLayoutWidgetKeyEvent(this, keyCode, event)
+ || super.onKeyDown(keyCode, event);
+ }
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (LauncherApplication.isScreenLarge()) {
+ return FocusHelper.handlePagedViewWidgetKeyEvent(this, keyCode, event)
+ || super.onKeyUp(keyCode, event);
+ } else {
+ return FocusHelper.handlePagedViewGridLayoutWidgetKeyEvent(this, keyCode, event)
+ || super.onKeyUp(keyCode, event);
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
if (mAlpha > 0) {
super.onDraw(canvas);
diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java
index 72f2d51..c0f80ae 100644
--- a/src/com/android/launcher2/ShortcutInfo.java
+++ b/src/com/android/launcher2/ShortcutInfo.java
@@ -148,12 +148,6 @@
return "ShortcutInfo(title=" + title.toString() + ")";
}
- @Override
- void unbind() {
- super.unbind();
- }
-
-
public static void dumpShortcutInfoList(String tag, String label,
ArrayList<ShortcutInfo> list) {
Log.d(tag, label + " size=" + list.size());
diff --git a/src/com/android/launcher2/ShortcutsAdapter.java b/src/com/android/launcher2/ShortcutsAdapter.java
index 93c500a..de73c3e 100644
--- a/src/com/android/launcher2/ShortcutsAdapter.java
+++ b/src/com/android/launcher2/ShortcutsAdapter.java
@@ -30,7 +30,7 @@
/**
* GridView adapter to show the list of applications and shortcuts
*/
-public class ShortcutsAdapter extends ArrayAdapter<ShortcutInfo> {
+public class ShortcutsAdapter extends ArrayAdapter<ShortcutInfo> {
private final LayoutInflater mInflater;
private final IconCache mIconCache;
diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java
deleted file mode 100644
index 251b3f9..0000000
--- a/src/com/android/launcher2/UserFolder.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.android.launcher2;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.launcher.R;
-
-/**
- * Folder which contains applications or shortcuts chosen by the user.
- *
- */
-public class UserFolder extends Folder implements DropTarget {
- private static final String TAG = "Launcher.UserFolder";
-
- public UserFolder(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- /**
- * Creates a new UserFolder, inflated from R.layout.user_folder.
- *
- * @param context The application's context.
- *
- * @return A new UserFolder.
- */
- static UserFolder fromXml(Context context) {
- return (UserFolder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
- }
-
- public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- final ItemInfo item = (ItemInfo) dragInfo;
- final int itemType = item.itemType;
- return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
- itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT)
- && item.container != mInfo.id;
- }
-
- public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- ShortcutInfo item;
- if (dragInfo instanceof ApplicationInfo) {
- // Came from all apps -- make a copy
- item = ((ApplicationInfo)dragInfo).makeShortcut();
- } else {
- item = (ShortcutInfo)dragInfo;
- }
- ((ShortcutsAdapter)mContent.getAdapter()).add(item);
- LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0);
- }
-
- public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- }
-
- public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- }
-
- public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- }
-
- @Override
- public void onDropCompleted(View target, Object dragInfo, boolean success) {
- if (success) {
- ShortcutsAdapter adapter = (ShortcutsAdapter)mContent.getAdapter();
- adapter.remove(mDragItem);
- }
- }
-
- public boolean isDropEnabled() {
- return true;
- }
-
- void bind(FolderInfo info) {
- super.bind(info);
- setContentAdapter(new ShortcutsAdapter(mContext, ((UserFolderInfo) info).contents));
- }
-
- // When the folder opens, we need to refresh the GridView's selection by
- // forcing a layout
- @Override
- void onOpen() {
- super.onOpen();
- requestFocus();
- }
-
- @Override
- public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- return null;
- }
-}
diff --git a/src/com/android/launcher2/UserFolderInfo.java b/src/com/android/launcher2/UserFolderInfo.java
deleted file mode 100644
index 0b8841c..0000000
--- a/src/com/android/launcher2/UserFolderInfo.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.ContentValues;
-
-import java.util.ArrayList;
-
-/**
- * Represents a folder containing shortcuts or apps.
- */
-class UserFolderInfo extends FolderInfo {
- /**
- * The apps and shortcuts
- */
- ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
-
- UserFolderInfo() {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER;
- }
-
- /**
- * Add an app or shortcut
- *
- * @param item
- */
- public void add(ShortcutInfo item) {
- contents.add(item);
- }
-
- /**
- * Remove an app or shortcut. Does not change the DB.
- *
- * @param item
- */
- public void remove(ShortcutInfo item) {
- contents.remove(item);
- }
-
- @Override
- void onAddToDatabase(ContentValues values) {
- super.onAddToDatabase(values);
- values.put(LauncherSettings.Favorites.TITLE, title.toString());
- }
-}
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
index 8ab22eb..ba25893 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -16,6 +16,8 @@
package com.android.launcher2;
+import java.util.Random;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -241,7 +243,7 @@
final float density = metrics.density;
sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
sIconContentSize = (int) resources.getDimension(R.dimen.app_icon_content_size);
}
sIconTextureWidth = sIconTextureHeight = sIconWidth + 2;
@@ -389,4 +391,8 @@
}
return n;
}
+
+ static int generateRandomId() {
+ return new Random(System.currentTimeMillis()).nextInt(1 << 24);
+ }
}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index e7865d2..1373996 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -16,8 +16,9 @@
package com.android.launcher2;
-import com.android.launcher.R;
-import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -37,7 +38,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -49,7 +49,6 @@
import android.graphics.RectF;
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.IBinder;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -66,9 +65,8 @@
import android.widget.TextView;
import android.widget.Toast;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
+import com.android.launcher.R;
+import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
/**
* The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -131,6 +129,7 @@
private int mDefaultPage;
private boolean mIsDragInProcess = false;
+ private boolean mIsDraggingOverIcon = false;
/**
* CellInfo for the cell that is currently being dragged
@@ -155,7 +154,7 @@
// return an (x, y) value from helper functions. Do NOT use them to maintain other state.
private int[] mTempCell = new int[2];
private int[] mTempEstimate = new int[2];
- private float[] mTempOriginXY = new float[2];
+ private float[] mDragViewVisualCenter = new float[2];
private float[] mTempDragCoordinates = new float[2];
private float[] mTempTouchCoordinates = new float[2];
private float[] mTempCellLayoutCenterCoordinates = new float[2];
@@ -213,6 +212,7 @@
WallpaperOffsetInterpolator mWallpaperOffset;
boolean mUpdateWallpaperOffsetImmediately = false;
boolean mSyncWallpaperOffsetWithScroll = true;
+ private Runnable mDelayedResizeRunnable;
// info about the last drag
private DragView mLastDragView;
@@ -249,7 +249,7 @@
super(context, attrs, defStyle);
mContentIsRefreshable = false;
- if (!LauncherApplication.isScreenXLarge()) {
+ if (!LauncherApplication.isScreenLarge()) {
mFadeInAdjacentScreens = false;
}
@@ -333,65 +333,48 @@
@Override
protected int getScrollMode() {
- if (LauncherApplication.isScreenXLarge()) {
+ if (LauncherApplication.isScreenLarge()) {
return SmoothPagedView.X_LARGE_MODE;
} else {
return SmoothPagedView.DEFAULT_MODE;
}
}
- @Override
- public void addView(View child, int index, LayoutParams params) {
+ private void onAddView(View child) {
if (!(child instanceof CellLayout)) {
throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
}
((CellLayout) child).setOnInterceptTouchListener(this);
child.setOnClickListener(this);
child.setClickable(true);
+ }
+ @Override
+ public void addView(View child, int index, LayoutParams params) {
+ onAddView(child);
super.addView(child, index, params);
}
@Override
public void addView(View child) {
- if (!(child instanceof CellLayout)) {
- throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
- }
- ((CellLayout) child).setOnInterceptTouchListener(this);
- child.setOnClickListener(this);
- child.setClickable(true);
+ onAddView(child);
super.addView(child);
}
@Override
public void addView(View child, int index) {
- if (!(child instanceof CellLayout)) {
- throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
- }
- ((CellLayout) child).setOnInterceptTouchListener(this);
- child.setOnClickListener(this);
- child.setClickable(true);
+ onAddView(child);
super.addView(child, index);
}
@Override
public void addView(View child, int width, int height) {
- if (!(child instanceof CellLayout)) {
- throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
- }
- ((CellLayout) child).setOnInterceptTouchListener(this);
- child.setOnClickListener(this);
- child.setClickable(true);
+ onAddView(child);
super.addView(child, width, height);
}
@Override
public void addView(View child, LayoutParams params) {
- if (!(child instanceof CellLayout)) {
- throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
- }
- ((CellLayout) child).setOnInterceptTouchListener(this);
- child.setOnClickListener(this);
- child.setClickable(true);
+ onAddView(child);
super.addView(child, params);
}
@@ -485,6 +468,10 @@
lp.cellVSpan = spanY;
}
+ if (spanX < 0 && spanY < 0) {
+ lp.isLockedToGrid = false;
+ }
+
// Get the canonical child id to uniquely represent this view in this screen
int childId = LauncherModel.getCellLayoutChildId(-1, screen, x, y, spanX, spanY);
boolean markCellsAsOccupied = !(child instanceof Folder);
@@ -645,6 +632,11 @@
}
mOverScrollMaxBackgroundAlpha = 0.0f;
mOverScrollPageIndex = -1;
+
+ if (mDelayedResizeRunnable != null) {
+ mDelayedResizeRunnable.run();
+ mDelayedResizeRunnable = null;
+ }
}
@Override
@@ -769,7 +761,8 @@
return offset;
}
private void syncWallpaperOffsetWithScroll() {
- if (LauncherApplication.isScreenXLarge()) {
+ final boolean enableWallpaperEffects = isHardwareAccelerated();
+ if (enableWallpaperEffects) {
mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());
}
}
@@ -1067,6 +1060,11 @@
@Override
protected void screenScrolled(int screenCenter) {
+ // If the screen is not xlarge, then don't rotate the CellLayouts
+ // NOTE: If we don't update the side pages alpha, then we should not hide the side pages.
+ // see unshrink().
+ if (!LauncherApplication.isScreenLarge()) return;
+
final int halfScreenSize = getMeasuredWidth() / 2;
for (int i = 0; i < getChildCount(); i++) {
@@ -1244,6 +1242,14 @@
}
@Override
+ public int getDescendantFocusability() {
+ if (mIsSmall) {
+ return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+ }
+ return super.getDescendantFocusability();
+ }
+
+ @Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
if (!mLauncher.isAllAppsVisible()) {
final Folder openFolder = getOpenFolder();
@@ -1255,19 +1261,6 @@
}
}
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- // (In XLarge mode, the workspace is shrunken below all apps, and responds to taps
- // ie when you click on a mini-screen, it zooms back to that screen)
- if (!LauncherApplication.isScreenXLarge() && mLauncher.isAllAppsVisible()) {
- return false;
- }
- }
-
- return super.dispatchTouchEvent(ev);
- }
-
void enableChildrenCache(int fromPage, int toPage) {
if (fromPage > toPage) {
final int temp = fromPage;
@@ -1297,27 +1290,32 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
- AllAppsPagedView allApps = (AllAppsPagedView)
- mLauncher.findViewById(R.id.all_apps_paged_view);
-
- if (mLauncher.isAllAppsVisible() && mShrinkState == ShrinkState.BOTTOM_HIDDEN
- && allApps != null) {
- if (ev.getAction() == MotionEvent.ACTION_UP &&
- allApps.getTouchState() == TOUCH_STATE_REST) {
-
- // Cancel any scrolling that is in progress.
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
- setCurrentPage(mCurrentPage);
-
- if (mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
- mLauncher.showWorkspace(true);
- }
- allApps.onTouchEvent(ev);
- return true;
+ if (mLauncher.isAllAppsVisible() && mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
+ PagedView appsPane;
+ if (LauncherApplication.isScreenLarge()) {
+ appsPane = (PagedView) mLauncher.findViewById(R.id.all_apps_paged_view);
} else {
- return allApps.onTouchEvent(ev);
+ appsPane = (PagedView) mLauncher.findViewById(R.id.apps_customize_pane_content);
+ }
+
+ if (appsPane != null) {
+ if (ev.getAction() == MotionEvent.ACTION_UP &&
+ appsPane.getTouchState() == TOUCH_STATE_REST) {
+
+ // Cancel any scrolling that is in progress.
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
+ setCurrentPage(mCurrentPage);
+
+ if (mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
+ mLauncher.showWorkspace(true);
+ }
+ appsPane.onTouchEvent(ev);
+ return true;
+ } else {
+ return appsPane.onTouchEvent(ev);
+ }
}
}
return super.onTouchEvent(ev);
@@ -1392,14 +1390,6 @@
// we use this to shrink the workspace for the all apps view and the customize view
public void shrink(ShrinkState shrinkState, boolean animated) {
- // In the launcher interaction model, we're never in the state where we're shrunken and
- // visible in the bottom of the screen, and then want to fade to being invisible.
- // After spring loaded mode ends, this method was getting called twice, the first time
- // with BOTTOM_VISIBLE (what we want) and a second time with BOTTOM_INVISIBLE (not
- // what we want). As a temporary solution, we just change the second call to BOTTOM_VISIBLE
- if (mIsSmall && mShrinkState == ShrinkState.BOTTOM_VISIBLE) {
- shrinkState = ShrinkState.BOTTOM_VISIBLE;
- }
if (mFirstLayout) {
// (mFirstLayout == "first layout has not happened yet")
// if we get a call to shrink() as part of our initialization (for example, if
@@ -1471,7 +1461,7 @@
int duration;
if (shrinkState == ShrinkState.BOTTOM_HIDDEN || shrinkState == ShrinkState.BOTTOM_VISIBLE) {
- duration = res.getInteger(R.integer.config_allAppsWorkspaceShrinkTime);
+ duration = res.getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
} else {
duration = res.getInteger(R.integer.config_customizeWorkspaceShrinkTime);
}
@@ -1556,30 +1546,35 @@
float offsetFromCenter = (wallpaperTravelHeight / (float) mWallpaperHeight) / 2f;
boolean isLandscape = display.getWidth() > display.getHeight();
- switch (shrinkState) {
- // animating in
- case TOP:
- // customize
- wallpaperOffset = 0.5f + offsetFromCenter;
- mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.46f : 0.44f);
- break;
- case MIDDLE:
- case SPRING_LOADED:
- wallpaperOffset = 0.5f;
- mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.34f : 0.32f);
- break;
- case BOTTOM_HIDDEN:
- case BOTTOM_VISIBLE:
- // allapps
- wallpaperOffset = 0.5f - offsetFromCenter;
- mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.34f : 0.32f);
- break;
+ final boolean enableWallpaperEffects = isHardwareAccelerated();
+ if (enableWallpaperEffects) {
+ switch (shrinkState) {
+ // animating in
+ case TOP:
+ // customize
+ wallpaperOffset = 0.5f + offsetFromCenter;
+ mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.46f : 0.44f);
+ break;
+ case MIDDLE:
+ case SPRING_LOADED:
+ wallpaperOffset = 0.5f;
+ mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.34f : 0.32f);
+ break;
+ case BOTTOM_HIDDEN:
+ case BOTTOM_VISIBLE:
+ // allapps
+ wallpaperOffset = 0.5f - offsetFromCenter;
+ mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.34f : 0.32f);
+ break;
+ }
}
setLayoutScale(1.0f);
if (animated) {
- mWallpaperOffset.setHorizontalCatchupConstant(0.46f);
- mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+ if (enableWallpaperEffects) {
+ mWallpaperOffset.setHorizontalCatchupConstant(0.46f);
+ mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+ }
mSyncWallpaperOffsetWithScroll = false;
@@ -1591,19 +1586,19 @@
final float oldVerticalWallpaperOffset = getVerticalWallpaperOffset();
final float newHorizontalWallpaperOffset = 0.5f;
final float newVerticalWallpaperOffset = wallpaperOffset;
- animWithInterpolator.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float b = (Float) animation.getAnimatedValue();
- final float a = 1f - b;
+ animWithInterpolator.addUpdateListener(new LauncherAnimatorUpdateListener() {
+ public void onAnimationUpdate(float a, float b) {
if (b == 0f) {
// an optimization, and required for correct behavior.
return;
}
fastInvalidate();
- setHorizontalWallpaperOffset(
+ if (enableWallpaperEffects) {
+ setHorizontalWallpaperOffset(
a * oldHorizontalWallpaperOffset + b * newHorizontalWallpaperOffset);
- setVerticalWallpaperOffset(
+ setVerticalWallpaperOffset(
a * oldVerticalWallpaperOffset + b * newVerticalWallpaperOffset);
+ }
for (int i = 0; i < screenCount; i++) {
final CellLayout cl = (CellLayout) getChildAt(i);
cl.fastInvalidate();
@@ -1621,7 +1616,7 @@
mAnimator.playTogether(animWithInterpolator);
mAnimator.addListener(mShrinkAnimationListener);
mAnimator.start();
- } else {
+ } else if (enableWallpaperEffects) {
setVerticalWallpaperOffset(wallpaperOffset);
setHorizontalWallpaperOffset(0.5f);
updateWallpaperOffsetImmediately();
@@ -1708,39 +1703,57 @@
for (int i = 0; i < screenCount; i++) {
CellLayout cl = (CellLayout) getChildAt(i);
cl.setIsDragOccuring(isDragHappening);
- switch (state) {
- case TOP:
- cl.setIsDefaultDropTarget(i == mCurrentPage);
- case BOTTOM_HIDDEN:
- case BOTTOM_VISIBLE:
- case SPRING_LOADED:
- if (state != ShrinkState.TOP) {
- cl.setIsDefaultDropTarget(false);
- }
- if (!isDragHappening) {
- // even if a drag isn't happening, we don't want to show a screen as
- // accepting drops if it doesn't have at least one free cell
- spanX = 1;
- spanY = 1;
- }
- // the page accepts drops if we can find at least one empty spot
- cl.setAcceptsDrops(cl.findCellForSpan(null, spanX, spanY));
- break;
- default:
- throw new RuntimeException("Unhandled ShrinkState " + state);
+ if (state == null) {
+ // If we are not in a shrunken state, mark all cell layouts as droppable (if they
+ // have the space)
+ cl.setAcceptsDrops(cl.findCellForSpan(null, spanX, spanY));
+ } else {
+ switch (state) {
+ case TOP:
+ cl.setIsDefaultDropTarget(i == mCurrentPage);
+ case BOTTOM_HIDDEN:
+ case BOTTOM_VISIBLE:
+ case SPRING_LOADED:
+ if (state != ShrinkState.TOP) {
+ cl.setIsDefaultDropTarget(false);
+ }
+ if (!isDragHappening) {
+ // even if a drag isn't happening, we don't want to show a screen as
+ // accepting drops if it doesn't have at least one free cell
+ spanX = 1;
+ spanY = 1;
+ }
+ // the page accepts drops if we can find at least one empty spot
+ cl.setAcceptsDrops(cl.findCellForSpan(null, spanX, spanY));
+ break;
+ default:
+ throw new RuntimeException("Unhandled ShrinkState " + state);
+ }
}
}
}
/*
- *
- * We call these methods (onDragStartedWithItemSpans/onDragStartedWithItemMinSize) whenever we
- * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
- *
- * These methods mark the appropriate pages as accepting drops (which alters their visual
- * appearance).
- *
- */
+ *
+ * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
+ * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
+ *
+ * These methods mark the appropriate pages as accepting drops (which alters their visual
+ * appearance).
+ *
+ */
+ public void onDragStartedWithItem(View v) {
+ mIsDragInProcess = true;
+
+ final Canvas canvas = new Canvas();
+
+ // We need to add extra padding to the bitmap to make room for the glow effect
+ final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
+
+ // The outline is used to visualize where the item will land if dropped
+ mDragOutline = createDragOutline(v, canvas, bitmapPadding);
+ }
+
public void onDragStartedWithItemSpans(int spanX, int spanY, Bitmap b) {
mIsDragInProcess = true;
@@ -1750,9 +1763,11 @@
final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
CellLayout cl = (CellLayout) getChildAt(0);
- int[] desiredSize = cl.cellSpansToSize(spanX, spanY);
+
+ int[] size = cl.cellSpansToSize(spanX, spanY);
+
// The outline is used to visualize where the item will land if dropped
- mDragOutline = createDragOutline(b, canvas, bitmapPadding, desiredSize[0], desiredSize[1]);
+ mDragOutline = createDragOutline(b, canvas, bitmapPadding, size[0], size[1]);
updateWhichPagesAcceptDropsDuringDrag(mShrinkState, spanX, spanY);
}
@@ -1800,8 +1815,8 @@
}
public void exitWidgetResizeMode() {
- final CellLayout currentLayout = (CellLayout) getChildAt(getCurrentPage());
- currentLayout.getChildrenLayout().clearAllResizeFrames();
+ DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+ dragLayer.clearAllResizeFrames();
}
void unshrink(boolean animated) {
@@ -1847,20 +1862,34 @@
for (int i = 0; i < screenCount; i++) {
final CellLayout cl = (CellLayout)getChildAt(i);
- float finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f;
+ float finalAlphaValue = 0f;
+ float rotation = 0f;
+ if (LauncherApplication.isScreenLarge()) {
+ finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f;
+
+ if (i < mCurrentPage) {
+ rotation = WORKSPACE_ROTATION;
+ } else if (i > mCurrentPage) {
+ rotation = -WORKSPACE_ROTATION;
+ }
+ } else {
+ // Don't hide the side panes on the phone if we don't also update the side pages
+ // alpha. See screenScrolled().
+ finalAlphaValue = 1f;
+ }
float finalAlphaMultiplierValue =
((i == mCurrentPage) && (mShrinkState != ShrinkState.SPRING_LOADED)) ?
0.0f : 1.0f;
- float rotation = 0.0f;
- if (i < mCurrentPage) {
- rotation = WORKSPACE_ROTATION;
- } else if (i > mCurrentPage) {
- rotation = -WORKSPACE_ROTATION;
+ float translation = 0f;
+
+ // If the screen is not xlarge, then don't rotate the CellLayouts
+ // NOTE: If we don't update the side pages alpha, then we should not hide the side
+ // pages. see unshrink().
+ if (LauncherApplication.isScreenLarge()) {
+ translation = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
}
- float translation = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
-
oldAlphas[i] = cl.getAlpha();
newAlphas[i] = finalAlphaValue;
if (animated) {
@@ -1893,56 +1922,62 @@
}
Display display = mLauncher.getWindowManager().getDefaultDisplay();
boolean isLandscape = display.getWidth() > display.getHeight();
- switch (mShrinkState) {
- // animating out
- case TOP:
- // customize
- if (animated) {
- mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.65f : 0.62f);
- mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.65f : 0.62f);
- mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
- }
- break;
- case MIDDLE:
- case SPRING_LOADED:
- if (animated) {
- mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.49f : 0.46f);
- mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.49f : 0.46f);
- mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
- }
- break;
- case BOTTOM_HIDDEN:
- case BOTTOM_VISIBLE:
- // all apps
- if (animated) {
- mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.65f : 0.65f);
- mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.65f : 0.65f);
- mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
- }
- break;
+ final boolean enableWallpaperEffects = isHardwareAccelerated();
+ if (enableWallpaperEffects) {
+ switch (mShrinkState) {
+ // animating out
+ case TOP:
+ // customize
+ if (animated) {
+ mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.65f : 0.62f);
+ mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.65f : 0.62f);
+ mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+ }
+ break;
+ case MIDDLE:
+ case SPRING_LOADED:
+ if (animated) {
+ mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.49f : 0.46f);
+ mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.49f : 0.46f);
+ mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+ }
+ break;
+ case BOTTOM_HIDDEN:
+ case BOTTOM_VISIBLE:
+ // all apps
+ if (animated) {
+ mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.65f : 0.65f);
+ mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.65f : 0.65f);
+ mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+ }
+ break;
+ }
}
if (animated) {
ValueAnimator animWithInterpolator =
ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
animWithInterpolator.setInterpolator(mZoomInInterpolator);
- final float oldHorizontalWallpaperOffset = getHorizontalWallpaperOffset();
- final float oldVerticalWallpaperOffset = getVerticalWallpaperOffset();
- final float newHorizontalWallpaperOffset = wallpaperOffsetForCurrentScroll();
- final float newVerticalWallpaperOffset = 0.5f;
- animWithInterpolator.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- final float b = (Float) animation.getAnimatedValue();
- final float a = 1f - b;
+ final float oldHorizontalWallpaperOffset = enableWallpaperEffects ?
+ getHorizontalWallpaperOffset() : 0;
+ final float oldVerticalWallpaperOffset = enableWallpaperEffects ?
+ getVerticalWallpaperOffset() : 0;
+ final float newHorizontalWallpaperOffset = enableWallpaperEffects ?
+ wallpaperOffsetForCurrentScroll() : 0;
+ final float newVerticalWallpaperOffset = enableWallpaperEffects ? 0.5f : 0;
+ animWithInterpolator.addUpdateListener(new LauncherAnimatorUpdateListener() {
+ public void onAnimationUpdate(float a, float b) {
if (b == 0f) {
// an optimization, but not required
return;
}
fastInvalidate();
- setHorizontalWallpaperOffset(
- a * oldHorizontalWallpaperOffset + b * newHorizontalWallpaperOffset);
- setVerticalWallpaperOffset(
- a * oldVerticalWallpaperOffset + b * newVerticalWallpaperOffset);
+ if (enableWallpaperEffects) {
+ setHorizontalWallpaperOffset(a * oldHorizontalWallpaperOffset
+ + b * newHorizontalWallpaperOffset);
+ setVerticalWallpaperOffset(a * oldVerticalWallpaperOffset
+ + b * newVerticalWallpaperOffset);
+ }
for (int i = 0; i < screenCount; i++) {
final CellLayout cl = (CellLayout) getChildAt(i);
cl.fastInvalidate();
@@ -1964,11 +1999,9 @@
ValueAnimator rotationAnim =
ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
rotationAnim.setInterpolator(new DecelerateInterpolator(2.0f));
- rotationAnim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
+ rotationAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+ public void onAnimationUpdate(float a, float b) {
// don't invalidate workspace because we did it above
- final float b = (Float) animation.getAnimatedValue();
- final float a = 1f - b;
if (b == 0f) {
// an optimization, but not required
return;
@@ -1986,9 +2019,11 @@
mAnimator.addListener(mUnshrinkAnimationListener);
mAnimator.start();
} else {
- setHorizontalWallpaperOffset(wallpaperOffsetForCurrentScroll());
- setVerticalWallpaperOffset(0.5f);
- updateWallpaperOffsetImmediately();
+ if (enableWallpaperEffects) {
+ setHorizontalWallpaperOffset(wallpaperOffsetForCurrentScroll());
+ setVerticalWallpaperOffset(0.5f);
+ updateWallpaperOffsetImmediately();
+ }
}
}
@@ -2009,7 +2044,8 @@
v.getDrawingRect(clipRect);
// For a TextView, adjust the clip rect so that we don't include the text label
- if (v instanceof BubbleTextView) {
+ if (v instanceof FolderIcon) {
+ } else if (v instanceof BubbleTextView) {
final BubbleTextView tv = (BubbleTextView) v;
clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
tv.getLayout().getLineTop(0);
@@ -2140,12 +2176,24 @@
final int bmpWidth = b.getWidth();
final int bmpHeight = b.getHeight();
+
child.getLocationOnScreen(mTempXY);
final int screenX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2;
final int screenY = (int) mTempXY[1] + (child.getHeight() - bmpHeight) / 2;
+
+ Rect dragRect = null;
+ if ((child instanceof BubbleTextView) && !(child instanceof FolderIcon)) {
+ int iconSize = getResources().getDimensionPixelSize(R.dimen.app_icon_size);
+ int top = child.getPaddingTop();
+ int left = (bmpWidth - iconSize) / 2;
+ int right = left + iconSize;
+ int bottom = top + iconSize;
+ dragRect = new Rect(left, top, right, bottom);
+ }
+
mLauncher.lockScreenOrientation();
- mDragController.startDrag(
- b, screenX, screenY, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
+ mDragController.startDrag(b, screenX, screenY, this, child.getTag(),
+ DragController.DRAG_ACTION_MOVE, dragRect);
b.recycle();
}
@@ -2167,15 +2215,15 @@
final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
// Based on the position of the drag view, find the top left of the original view
- int viewX = dragViewX + (dragView.getWidth() - child.getWidth()) / 2;
- int viewY = dragViewY + (dragView.getHeight() - child.getHeight()) / 2;
- viewX += getResources().getInteger(R.integer.config_dragViewOffsetX);
- viewY += getResources().getInteger(R.integer.config_dragViewOffsetY);
+ int viewX = dragViewX + (dragView.getWidth() - child.getMeasuredWidth()) / 2;
+ int viewY = dragViewY + (dragView.getHeight() - child.getMeasuredHeight()) / 2;
+
+ CellLayout layout = (CellLayout) parent;
// Set its old pos (in the new parent's coordinates); it will be animated
// in animateViewIntoPosition after the next layout pass
- lp.oldX = viewX - (parent.getLeft() - mScrollX);
- lp.oldY = viewY - (parent.getTop() - mScrollY);
+ lp.oldX = viewX - (layout.getLeft() + layout.getLeftPadding() - mScrollX);
+ lp.oldY = viewY - (layout.getTop() + layout.getTopPadding() - mScrollY);
}
/*
@@ -2187,8 +2235,8 @@
final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
// Convert the animation params to be relative to the Workspace, not the CellLayout
- final int fromX = lp.oldX + parent.getLeft();
- final int fromY = lp.oldY + parent.getTop();
+ final int fromX = lp.oldX + parent.getLeft() + parent.getLeftPadding();
+ final int fromY = lp.oldY + parent.getTop() + parent.getTopPadding();
final int dx = lp.x - lp.oldX;
final int dy = lp.y - lp.oldY;
@@ -2271,23 +2319,80 @@
return true;
}
+ boolean willCreateUserFolder(ItemInfo info, CellLayout target, int originX, int originY) {
+ mTargetCell = findNearestArea(originX, originY,
+ 1, 1, target,
+ mTargetCell);
+
+ View v = target.getChildAt(mTargetCell[0], mTargetCell[1]);
+ boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
+ mDragInfo.cellY == mTargetCell[1]);
+
+ if (v == null || hasntMoved) return false;
+
+ boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
+ boolean willBecomeShortcut =
+ (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+ info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
+
+ return (aboveShortcut && willBecomeShortcut);
+ }
+
+ boolean createUserFolderIfNecessary(View newView, CellLayout target, int originX,
+ int originY, boolean external) {
+ int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
+ int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
+
+ // First we find the cell nearest to point at which the item is dropped, without
+ // any consideration to whether there is an item there.
+ mTargetCell = findNearestArea(originX, originY,
+ spanX, spanY, target,
+ mTargetCell);
+
+ View v = target.getChildAt(mTargetCell[0], mTargetCell[1]);
+ boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
+ mDragInfo.cellY == mTargetCell[1]);
+
+ if (v == null || hasntMoved) return false;
+
+ final int screen = (mTargetCell == null) ?
+ mDragInfo.screen : indexOfChild(target);
+
+ boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
+ boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
+
+ if (aboveShortcut && willBecomeShortcut) {
+ ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();
+ ShortcutInfo destInfo = (ShortcutInfo) v.getTag();
+ // if the drag started here, we need to remove it from the workspace
+ if (!external) {
+ int fromScreen = mDragInfo.screen;
+ CellLayout sourceLayout = (CellLayout) getChildAt(fromScreen);
+ sourceLayout.removeView(newView);
+ }
+
+ target.removeView(v);
+ FolderIcon fi = mLauncher.addFolder(screen, mTargetCell[0], mTargetCell[1]);
+ destInfo.cellX = -1;
+ destInfo.cellY = -1;
+ sourceInfo.cellX = -1;
+ sourceInfo.cellY = -1;
+ fi.addItem(destInfo);
+ fi.addItem(sourceInfo);
+ return true;
+ }
+ return false;
+ }
+
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
- boolean largeOrSpringLoaded = !mIsSmall || mWasSpringLoadedOnDragExit;
- int originX = largeOrSpringLoaded ? x - xOffset : x - xOffset + dragView.getWidth() / 2;
- int originY = largeOrSpringLoaded ? y - yOffset : y - yOffset + dragView.getHeight() / 2;
- if (mIsSmall || mIsInUnshrinkAnimation) {
- // get originX and originY in the local coordinate system of the screen
- mTempOriginXY[0] = originX;
- mTempOriginXY[1] = originY;
- mapPointFromSelfToChild(mDragTargetLayout, mTempOriginXY);
- originX = (int)mTempOriginXY[0];
- originY = (int)mTempOriginXY[1];
- if (!largeOrSpringLoaded) {
- originX -= mDragTargetLayout.getCellWidth() / 2;
- originY -= mDragTargetLayout.getCellHeight() / 2;
- }
+ mDragViewVisualCenter = getDragViewVisualCenter(x, y, xOffset, yOffset, dragView,
+ mDragViewVisualCenter);
+
+ // We want the point to be mapped to the dragTarget.
+ if (mDragTargetLayout != null) {
+ mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
}
// When you are in customization mode and drag to a particular screen, make that the
@@ -2300,21 +2405,25 @@
}
if (source != this) {
- final int[] touchXY = new int[] { originX, originY };
- if ((mIsSmall || mIsInUnshrinkAnimation) && !mLauncher.isAllAppsVisible()) {
+ final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
+ (int) mDragViewVisualCenter[1] };
+ if (LauncherApplication.isScreenLarge() && (mIsSmall || mIsInUnshrinkAnimation)
+ && !mLauncher.isAllAppsVisible()) {
// When the workspace is shrunk and the drop comes from customize, don't actually
// add the item to the screen -- customize will do this itself
((ItemInfo) dragInfo).dropPos = touchXY;
return;
}
- onDropExternal(touchXY, dragInfo, mDragTargetLayout, false);
+ onDropExternal(touchXY, dragInfo, mDragTargetLayout, false, dragView);
} else if (mDragInfo != null) {
final View cell = mDragInfo.cell;
CellLayout dropTargetLayout = mDragTargetLayout;
+ boolean dropInscrollArea = false;
// Handle the case where the user drops when in the scroll area.
// This is treated as a drop on the adjacent page.
if (dropTargetLayout == null && mInScrollArea) {
+ dropInscrollArea = true;
if (mPendingScrollDirection == DragController.SCROLL_LEFT) {
dropTargetLayout = (CellLayout) getChildAt(mCurrentPage - 1);
} else if (mPendingScrollDirection == DragController.SCROLL_RIGHT) {
@@ -2324,13 +2433,22 @@
if (dropTargetLayout != null) {
// Move internally
- mTargetCell = findNearestVacantArea(originX, originY,
- mDragInfo.spanX, mDragInfo.spanY, cell, dropTargetLayout,
- mTargetCell);
-
final int screen = (mTargetCell == null) ?
mDragInfo.screen : indexOfChild(dropTargetLayout);
+ // If the item being dropped is a shortcut and the nearest drop cell also contains
+ // a shortcut, then create a folder with the two shortcuts.
+ if (!dropInscrollArea && createUserFolderIfNecessary(cell, dropTargetLayout,
+ (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], false)) {
+ return;
+ }
+
+ // Aside from the special case where we're dropping a shortcut onto a shortcut,
+ // we need to find the nearest cell location that is vacant
+ mTargetCell = findNearestVacantArea((int) mDragViewVisualCenter[0],
+ (int) mDragViewVisualCenter[1], mDragInfo.spanX, mDragInfo.spanY, cell,
+ dropTargetLayout, mTargetCell);
+
if (screen != mCurrentPage) {
snapToPage(screen);
}
@@ -2353,7 +2471,6 @@
mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
if (cell instanceof LauncherAppWidgetHostView) {
- final CellLayoutChildren children = dropTargetLayout.getChildrenLayout();
final CellLayout cellLayout = dropTargetLayout;
// We post this call so that the widget has a chance to be placed
// in its final location
@@ -2361,10 +2478,21 @@
final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
if (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
+ final Runnable resizeRunnable = new Runnable() {
+ public void run() {
+ DragLayer dragLayer = (DragLayer)
+ mLauncher.findViewById(R.id.drag_layer);
+ dragLayer.addResizeFrame(info, hostView,
+ cellLayout);
+ }
+ };
post(new Runnable() {
public void run() {
- children.addResizeFrame(info, hostView,
- cellLayout);
+ if (!isPageMoving()) {
+ resizeRunnable.run();
+ } else {
+ mDelayedResizeRunnable = resizeRunnable;
+ }
}
});
}
@@ -2378,14 +2506,30 @@
final CellLayout parent = (CellLayout) cell.getParent().getParent();
+ int loc[] = new int[2];
+ getViewLocationRelativeToSelf(dragView, loc);
+
// Prepare it to be animated into its new position
// This must be called after the view has been re-parented
- setPositionForDropAnimation(dragView, originX, originY, parent, cell);
+ setPositionForDropAnimation(dragView, loc[0], loc[1], parent, cell);
boolean animateDrop = !mWasSpringLoadedOnDragExit;
parent.onDropChild(cell, animateDrop);
}
}
+ private void getViewLocationRelativeToSelf(View v, int[] location) {
+ getLocationOnScreen(location);
+ int x = location[0];
+ int y = location[1];
+
+ v.getLocationOnScreen(location);
+ int vX = location[0];
+ int vY = location[1];
+
+ location[0] = vX - x;
+ location[1] = vY - y;
+ }
+
public void onDragEnter(DragSource source, int x, int y, int xOffset,
int yOffset, DragView dragView, Object dragInfo) {
mDragTargetLayout = null; // Reset the drag state
@@ -2614,11 +2758,11 @@
xy[1] -= (mScrollY - v.getTop());
}
- static private float squaredDistance(float[] point1, float[] point2) {
+ static private float squaredDistance(float[] point1, float[] point2) {
float distanceX = point1[0] - point2[0];
float distanceY = point2[1] - point2[1];
return distanceX * distanceX + distanceY * distanceY;
- }
+ }
/*
*
@@ -2716,38 +2860,79 @@
return bestMatchingScreen;
}
+ // This is used to compute the visual center of the dragView. This point is then
+ // used to visualize drop locations and determine where to drop an item. The idea is that
+ // the visual center represents the user's interpretation of where the item is, and hence
+ // is the appropriate point to use when determining drop location.
+ private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
+ DragView dragView, float[] recycle) {
+ float res[];
+ if (recycle == null) {
+ res = new float[2];
+ } else {
+ res = recycle;
+ }
+
+ // First off, the drag view has been shifted in a way that is not represented in the
+ // x and y values or the x/yOffsets. Here we account for that shift.
+ x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);
+ y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
+
+ // These represent the visual top and left of drag view if a dragRect was provided.
+ // If a dragRect was not provided, then they correspond to the actual view left and
+ // top, as the dragRect is in that case taken to be the entire dragView.
+ // R.dimen.dragViewOffsetY.
+ int left = x - xOffset;
+ int top = y - yOffset;
+
+ // In order to find the visual center, we shift by half the dragRect
+ res[0] = left + dragView.getDragRegion().width() / 2;
+ res[1] = top + dragView.getDragRegion().height() / 2;
+
+ return res;
+ }
+
public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
// When touch is inside the scroll area, skip dragOver actions for the current screen
if (!mInScrollArea) {
CellLayout layout;
- int originX = x - xOffset;
- int originY = y - yOffset;
+ int left = x - xOffset;
+ int top = y - yOffset;
+
+ mDragViewVisualCenter = getDragViewVisualCenter(x, y, xOffset, yOffset, dragView,
+ mDragViewVisualCenter);
+
boolean shrunken = mIsSmall || mIsInUnshrinkAnimation;
if (shrunken) {
mLastDragView = dragView;
- mLastDragOriginX = originX;
- mLastDragOriginY = originY;
+ mLastDragOriginX = left;
+ mLastDragOriginY = top;
mLastDragXOffset = xOffset;
mLastDragYOffset = yOffset;
- layout = findMatchingPageForDragOver(dragView, originX, originY, xOffset, yOffset);
+ layout = findMatchingPageForDragOver(dragView, left, top, xOffset, yOffset);
- if (layout != mDragTargetLayout) {
+ if (layout != null && layout != mDragTargetLayout) {
if (mDragTargetLayout != null) {
mDragTargetLayout.setIsDragOverlapping(false);
mSpringLoadedDragController.onDragExit();
}
mDragTargetLayout = layout;
- // In spring-loaded mode, we still want the user to be able to hover over a
- // full screen (which is traditionally set to not accept drops) if they want to
- // get to pages beyond the screen that is full.
- boolean allowDragOver = (mDragTargetLayout != null) &&
- (mDragTargetLayout.getAcceptsDrops() ||
- (mShrinkState == ShrinkState.SPRING_LOADED));
- if (allowDragOver) {
- mDragTargetLayout.setIsDragOverlapping(true);
- mSpringLoadedDragController.onDragEnter(
- mDragTargetLayout, mShrinkState == ShrinkState.SPRING_LOADED);
+
+ // Workaround the fact that we don't actually want spring-loaded mode in phone
+ // UI yet.
+ if (LauncherApplication.isScreenLarge()) {
+ // In spring-loaded mode, we still want the user to be able to hover over a
+ // full screen (which is traditionally set to not accept drops) if they want
+ // to get to pages beyond the screen that is full.
+ boolean allowDragOver = (mDragTargetLayout != null) &&
+ (mDragTargetLayout.getAcceptsDrops() ||
+ (mShrinkState == ShrinkState.SPRING_LOADED));
+ if (allowDragOver) {
+ mDragTargetLayout.setIsDragOverlapping(true);
+ mSpringLoadedDragController.onDragEnter(
+ mDragTargetLayout, mShrinkState == ShrinkState.SPRING_LOADED);
+ }
}
}
} else {
@@ -2776,35 +2961,23 @@
}
}
- if (source instanceof AllAppsPagedView) {
- // This is a hack to fix the point used to determine which cell an icon from
- // the all apps screen is over
- if (item != null && item.spanX == 1 && layout != null) {
- int dragRegionLeft = (dragView.getWidth() - layout.getCellWidth()) / 2;
-
- originX += dragRegionLeft - dragView.getDragRegionLeft();
- if (dragView.getDragRegionWidth() != layout.getCellWidth()) {
- dragView.setDragRegion(dragView.getDragRegionLeft(),
- dragView.getDragRegionTop(),
- layout.getCellWidth(),
- dragView.getDragRegionHeight());
- }
- }
- } else if (source == this) {
- // When dragging from the workspace, the drag view is slightly bigger than
- // the original view, and offset vertically. Adjust to account for this.
- final View origView = mDragInfo.cell;
- originX += (dragView.getMeasuredWidth() - origView.getWidth()) / 2;
- originY += (dragView.getMeasuredHeight() - origView.getHeight()) / 2
- + dragView.getOffsetY();
- }
-
if (mDragTargetLayout != null) {
final View child = (mDragInfo == null) ? null : mDragInfo.cell;
- float[] localOrigin = { originX, originY };
- mapPointFromSelfToChild(mDragTargetLayout, localOrigin, null);
- mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
- (int) localOrigin[0], (int) localOrigin[1], item.spanX, item.spanY);
+ // We want the point to be mapped to the dragTarget.
+ mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
+ ItemInfo info = (ItemInfo) dragInfo;
+
+ if (!willCreateUserFolder(info, mDragTargetLayout,
+ (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1])) {
+ mIsDraggingOverIcon = false;
+ mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
+ (int) mDragViewVisualCenter[0],
+ (int) mDragViewVisualCenter[1],
+ item.spanX, item.spanY);
+ } else if (!mIsDraggingOverIcon) {
+ mIsDraggingOverIcon = true;
+ mDragTargetLayout.clearDragOutlines();
+ }
}
}
}
@@ -2850,6 +3023,11 @@
return false;
}
+ private void onDropExternal(int[] touchXY, Object dragInfo,
+ CellLayout cellLayout, boolean insertAtFirst) {
+ onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);
+ }
+
/**
* Drop an item that didn't originate on one of the workspace screens.
* It may have come from Launcher (e.g. from all apps or customize), or it may have
@@ -2859,7 +3037,7 @@
* to add an item to one of the workspace screens.
*/
private void onDropExternal(int[] touchXY, Object dragInfo,
- CellLayout cellLayout, boolean insertAtFirst) {
+ CellLayout cellLayout, boolean insertAtFirst, DragView dragView) {
int screen = indexOfChild(cellLayout);
if (dragInfo instanceof PendingAddItemInfo) {
PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
@@ -2869,9 +3047,6 @@
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
break;
- case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
- mLauncher.addLiveFolderFromDrop(info.componentName, screen, touchXY);
- break;
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY);
break;
@@ -2894,18 +3069,26 @@
view = mLauncher.createShortcut(R.layout.application, cellLayout,
(ShortcutInfo) info);
break;
- case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
- cellLayout, (UserFolderInfo) info, mIconCache);
+ cellLayout, (FolderInfo) info, mIconCache);
break;
default:
throw new IllegalStateException("Unknown item type: " + info.itemType);
}
+ // If the item being dropped is a shortcut and the nearest drop cell also contains
+ // a shortcut, then create a folder with the two shortcuts.
+ if (touchXY != null && createUserFolderIfNecessary(view, cellLayout, touchXY[0],
+ touchXY[1], true)) {
+ return;
+ }
+
mTargetCell = new int[2];
if (touchXY != null) {
// when dragging and dropping, just find the closest free spot
- cellLayout.findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, mTargetCell);
+ mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, null, cellLayout,
+ mTargetCell);
} else {
cellLayout.findCellForSpan(mTargetCell, 1, 1);
}
@@ -2915,6 +3098,15 @@
cellLayout.onDropChild(view, animateDrop);
cellLayout.animateDrop();
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
+ cellLayout.getChildrenLayout().measureChild(view);
+
+ if (dragView != null) {
+ // we have the visual center of the drag view, we need to find the actual
+ // left and top of the dragView.
+ int loc[] = new int[2];
+ getViewLocationRelativeToSelf(dragView, loc);
+ setPositionForDropAnimation(dragView, loc[0], loc[1], cellLayout, view);
+ }
LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
LauncherSettings.Favorites.CONTAINER_DESKTOP, screen,
@@ -2942,16 +3134,24 @@
/**
* Calculate the nearest cell where the given object would be dropped.
+ *
+ * pixelX and pixelY should be in the coordinate system of layout
*/
private int[] findNearestVacantArea(int pixelX, int pixelY,
int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) {
-
- int localPixelX = pixelX - (layout.getLeft() - mScrollX);
- int localPixelY = pixelY - (layout.getTop() - mScrollY);
-
- // Find the best target drop location
return layout.findNearestVacantArea(
- localPixelX, localPixelY, spanX, spanY, ignoreView, recycle);
+ pixelX, pixelY, spanX, spanY, ignoreView, recycle);
+ }
+
+ /**
+ * Calculate the nearest cell where the given object would be dropped.
+ *
+ * pixelX and pixelY should be in the coordinate system of layout
+ */
+ private int[] findNearestArea(int pixelX, int pixelY,
+ int spanX, int spanY, CellLayout layout, int[] recycle) {
+ return layout.findNearestArea(
+ pixelX, pixelY, spanX, spanY, recycle);
}
void setLauncher(Launcher launcher) {
@@ -3104,6 +3304,21 @@
return null;
}
+ void clearDropTargets() {
+ final int screenCount = getChildCount();
+
+ for (int i = 0; i < screenCount; i++) {
+ final CellLayout layoutParent = (CellLayout) getChildAt(i);
+ final ViewGroup layout = layoutParent.getChildrenLayout();
+ int childCount = layout.getChildCount();
+ for (int j = 0; j < childCount; j++) {
+ View v = layout.getChildAt(j);
+ if (v instanceof DropTarget) {
+ mDragController.removeDropTarget((DropTarget) v);
+ }
+ }
+ }
+ }
void removeItems(final ArrayList<ApplicationInfo> apps) {
final int screenCount = getChildCount();
@@ -3144,8 +3359,8 @@
}
}
}
- } else if (tag instanceof UserFolderInfo) {
- final UserFolderInfo info = (UserFolderInfo) tag;
+ } else if (tag instanceof FolderInfo) {
+ final FolderInfo info = (FolderInfo) tag;
final ArrayList<ShortcutInfo> contents = info.contents;
final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1);
final int contentsCount = contents.size();
@@ -3173,20 +3388,6 @@
if (folder != null)
folder.notifyDataSetChanged();
}
- } else if (tag instanceof LiveFolderInfo) {
- final LiveFolderInfo info = (LiveFolderInfo) tag;
- final Uri uri = info.uri;
- final ProviderInfo providerInfo = manager.resolveContentProvider(
- uri.getAuthority(), 0);
-
- if (providerInfo != null) {
- for (String packageName: packageNames) {
- if (packageName.equals(providerInfo.packageName)) {
- LauncherModel.deleteItemFromDatabase(mLauncher, info);
- childrenToRemove.add(view);
- }
- }
- }
} else if (tag instanceof LauncherAppWidgetInfo) {
final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
final AppWidgetProviderInfo provider =