am f7be630c: (-s ours) Import revised translations. DO NOT MERGE
* commit 'f7be630c94a9a5bfd8992d5b538f81a8e894b552':
Import revised translations. DO NOT MERGE
diff --git a/Android.mk b/Android.mk
index 5285e18..89e626b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,6 +14,8 @@
# limitations under the License.
#
+ifneq ($(TARGET_SIMULATOR),true)
+
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -21,7 +23,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-common
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-subdir-java-files) $(call all-renderscript-files-under, src)
LOCAL_PACKAGE_NAME := Launcher2
LOCAL_CERTIFICATE := shared
@@ -31,3 +33,5 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
include $(BUILD_PACKAGE)
+
+endif
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 84ee599..5d0f323 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -66,7 +66,9 @@
android:name="com.android.launcher2.LauncherApplication"
android:process="@string/process"
android:label="@string/application_name"
- android:icon="@drawable/ic_launcher_home">
+ android:icon="@drawable/ic_launcher_home"
+ android:hardwareAccelerated="@bool/config_hardwareAccelerated"
+ android:largeHeap="true">
<activity
android:name="com.android.launcher2.Launcher"
@@ -74,8 +76,7 @@
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/Theme"
- android:screenOrientation="nosensor"
- android:windowSoftInputMode="stateUnspecified|adjustPan">
+ android:windowSoftInputMode="stateUnspecified|adjustNothing">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
@@ -86,14 +87,17 @@
<activity
android:name="com.android.launcher2.WallpaperChooser"
+ style="@style/config_orientation"
android:label="@string/pick_wallpaper"
android:icon="@drawable/ic_launcher_wallpaper"
- android:screenOrientation="nosensor"
+ android:theme="@style/Theme.WallpaperPicker"
android:finishOnCloseSystemDialogs="true">
<intent-filter>
<action android:name="android.intent.action.SET_WALLPAPER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+ <meta-data android:name="android.wallpaper.preview"
+ android:resource="@xml/wallpaper_picker_preview" />
</activity>
<!-- Intent received used to install shortcuts from other applications -->
diff --git a/CleanSpec.mk b/CleanSpec.mk
index b84e1b6..444dbd8 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -44,6 +44,8 @@
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(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 1187fd8a..699f23e 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -2,6 +2,33 @@
public void previousScreen(android.view.View);
public void nextScreen(android.view.View);
public void launchHotSeat(android.view.View);
+ public void onClickSearchButton(android.view.View);
+ public void onClickVoiceButton(android.view.View);
+ public void onClickConfigureButton(android.view.View);
+ public void onClickAllAppsButton(android.view.View);
+ public void onClickAppMarketButton(android.view.View);
+}
+
+-keep class com.android.launcher2.CellLayout {
+ public float getBackgroundAlpha();
+ public void setBackgroundAlpha(float);
+ public float getDimmableProgress();
+ public void setDimmableProgress(float);
+ public float getHoverScale();
+ public void setHoverScale(float);
+ public float getHoverAlpha();
+ public void setHoverAlpha(float);
+}
+
+-keep class com.android.launcher2.Workspace {
+ public float getBackgroundAlpha();
+ public void setBackgroundAlpha(float);
+ public float getChildrenOutlineAlpha();
+ public void setChildrenOutlineAlpha(float);
+ public void setVerticalWallpaperOffset(float);
+ public float getVerticalWallpaperOffset();
+ public void setHorizontalWallpaperOffset(float);
+ public float getHorizontalWallpaperOffset();
}
-keep class com.android.launcher2.AllApps3D$Defines {
diff --git a/res/anim/all_apps_zoom_in.xml b/res/anim/all_apps_zoom_in.xml
new file mode 100644
index 0000000..644d1cf
--- /dev/null
+++ b/res/anim/all_apps_zoom_in.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/decelerate_interpolator"
+ android:shareInterpolator="true">
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0%p"
+ android:toXDelta="0%p"
+ android:fromYDelta="-20%p"
+ android:toYDelta="0%p"
+ android:duration="500" />
+ <scale
+ android:fromXScale="5.0"
+ android:toXScale="1.0"
+ android:fromYScale="5.0"
+ android:toYScale="1.0"
+ android:pivotX="50%"
+ android:pivotY="100%"
+ android:duration="500" />
+</set>
diff --git a/res/anim/all_apps_zoom_out.xml b/res/anim/all_apps_zoom_out.xml
new file mode 100644
index 0000000..23a8712
--- /dev/null
+++ b/res/anim/all_apps_zoom_out.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:shareInterpolator="true">
+ <translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0%p"
+ android:toXDelta="0%p"
+ android:fromYDelta="0%p"
+ android:toYDelta="-20%p"
+ android:duration="500" />
+ <scale
+ android:fromXScale="1.0"
+ android:toXScale="5.0"
+ android:fromYScale="1.0"
+ android:toYScale="5.0"
+ android:pivotX="50%"
+ android:pivotY="100%"
+ android:duration="500" />
+</set>
diff --git a/res/anim/home_customization_drawer_slide_down.xml b/res/anim/home_customization_drawer_slide_down.xml
new file mode 100644
index 0000000..b3041c7
--- /dev/null
+++ b/res/anim/home_customization_drawer_slide_down.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0%p"
+ android:toXDelta="0%p"
+ android:fromYDelta="0%p"
+ android:toYDelta="100%p"
+
+ android:duration="500" />
diff --git a/res/anim/home_customization_drawer_slide_up.xml b/res/anim/home_customization_drawer_slide_up.xml
new file mode 100644
index 0000000..3df2320
--- /dev/null
+++ b/res/anim/home_customization_drawer_slide_up.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromXDelta="0%p"
+ android:toXDelta="0%p"
+ android:fromYDelta="100%p"
+ android:toYDelta="0%p"
+
+ android:duration="500" />
diff --git a/res/anim/paged_view_click_feedback.xml b/res/anim/paged_view_click_feedback.xml
new file mode 100644
index 0000000..d1e6e23
--- /dev/null
+++ b/res/anim/paged_view_click_feedback.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.5"
+ android:duration="75"
+ android:fillAfter="true"
+ android:repeatCount="1"
+ android:repeatMode="reverse" />
diff --git a/res/color/tab_widget_indicator_color.xml b/res/color/tab_widget_indicator_color.xml
new file mode 100644
index 0000000..cbe9e3e
--- /dev/null
+++ b/res/color/tab_widget_indicator_color.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true" android:color="#FFEFEFEF" />
+ <item android:color="#909090" />
+</selector>
diff --git a/res/drawable-hdpi/default_widget_preview.9.png b/res/drawable-hdpi/default_widget_preview.9.png
new file mode 100644
index 0000000..833daff
--- /dev/null
+++ b/res/drawable-hdpi/default_widget_preview.9.png
Binary files differ
diff --git a/res/drawable-hdpi/gardening_crosshairs.png b/res/drawable-hdpi/gardening_crosshairs.png
new file mode 100644
index 0000000..fca6036
--- /dev/null
+++ b/res/drawable-hdpi/gardening_crosshairs.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_browser_focused.png b/res/drawable-hdpi/hotseat_browser_focused.png
index 25969ca..4ab51dd 100644
--- a/res/drawable-hdpi/hotseat_browser_focused.png
+++ b/res/drawable-hdpi/hotseat_browser_focused.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_browser_normal.png b/res/drawable-hdpi/hotseat_browser_normal.png
index 0dbdbe7..77ae927 100644
--- a/res/drawable-hdpi/hotseat_browser_normal.png
+++ b/res/drawable-hdpi/hotseat_browser_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_browser_pressed.png b/res/drawable-hdpi/hotseat_browser_pressed.png
index 3b872bf..cfe963b 100644
--- a/res/drawable-hdpi/hotseat_browser_pressed.png
+++ b/res/drawable-hdpi/hotseat_browser_pressed.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_phone_focused.png b/res/drawable-hdpi/hotseat_phone_focused.png
index 3172d7f..f81f0a8 100644
--- a/res/drawable-hdpi/hotseat_phone_focused.png
+++ b/res/drawable-hdpi/hotseat_phone_focused.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_phone_normal.png b/res/drawable-hdpi/hotseat_phone_normal.png
index 61ef7e6..391802e 100644
--- a/res/drawable-hdpi/hotseat_phone_normal.png
+++ b/res/drawable-hdpi/hotseat_phone_normal.png
Binary files differ
diff --git a/res/drawable-hdpi/hotseat_phone_pressed.png b/res/drawable-hdpi/hotseat_phone_pressed.png
index 7bf8f48..a6c2baf 100644
--- a/res/drawable-hdpi/hotseat_phone_pressed.png
+++ b/res/drawable-hdpi/hotseat_phone_pressed.png
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_left.9.png b/res/drawable-hdpi/page_hover_left.9.png
new file mode 100644
index 0000000..1bf1565
--- /dev/null
+++ b/res/drawable-hdpi/page_hover_left.9.png
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_right.9.png b/res/drawable-hdpi/page_hover_right.9.png
new file mode 100644
index 0000000..7995f69
--- /dev/null
+++ b/res/drawable-hdpi/page_hover_right.9.png
Binary files differ
diff --git a/res/drawable-hdpi/pattern_carbon_fiber_dark.png b/res/drawable-hdpi/pattern_carbon_fiber_dark.png
deleted file mode 100644
index 427936f..0000000
--- a/res/drawable-hdpi/pattern_carbon_fiber_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/placeholder_google.png b/res/drawable-hdpi/placeholder_google.png
deleted file mode 100644
index 923c8b8..0000000
--- a/res/drawable-hdpi/placeholder_google.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/pressed_application_background.9.png b/res/drawable-hdpi/pressed_application_background.9.png
new file mode 100644
index 0000000..291af02
--- /dev/null
+++ b/res/drawable-hdpi/pressed_application_background.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_selected_focused_holo.9.png b/res/drawable-hdpi/tab_selected_focused_holo.9.png
new file mode 100644
index 0000000..1ba35d5
--- /dev/null
+++ b/res/drawable-hdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_selected_holo.9.png b/res/drawable-hdpi/tab_selected_holo.9.png
new file mode 100644
index 0000000..ef913cc
--- /dev/null
+++ b/res/drawable-hdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_selected_pressed_focused_holo.9.png b/res/drawable-hdpi/tab_selected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..d7e9688
--- /dev/null
+++ b/res/drawable-hdpi/tab_selected_pressed_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_selected_pressed_holo.9.png b/res/drawable-hdpi/tab_selected_pressed_holo.9.png
new file mode 100644
index 0000000..b8b1fcf
--- /dev/null
+++ b/res/drawable-hdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_unselected_focused_holo.9.png b/res/drawable-hdpi/tab_unselected_focused_holo.9.png
new file mode 100644
index 0000000..256e8e7
--- /dev/null
+++ b/res/drawable-hdpi/tab_unselected_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_unselected_holo.9.png b/res/drawable-hdpi/tab_unselected_holo.9.png
new file mode 100644
index 0000000..db6fc14
--- /dev/null
+++ b/res/drawable-hdpi/tab_unselected_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_unselected_pressed_focused_holo.9.png b/res/drawable-hdpi/tab_unselected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..d17b820
--- /dev/null
+++ b/res/drawable-hdpi/tab_unselected_pressed_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_unselected_pressed_holo.9.png b/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
new file mode 100644
index 0000000..a344994
--- /dev/null
+++ b/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_divider.png b/res/drawable-hdpi/widget_divider.png
new file mode 100644
index 0000000..2f92d60
--- /dev/null
+++ b/res/drawable-hdpi/widget_divider.png
Binary files differ
diff --git a/res/drawable-mdpi/all_apps_button_focused.png b/res/drawable-mdpi/all_apps_button_focused.png
index a9d5a3f..dd77f80 100644
--- a/res/drawable-mdpi/all_apps_button_focused.png
+++ b/res/drawable-mdpi/all_apps_button_focused.png
Binary files differ
diff --git a/res/drawable-mdpi/all_apps_button_normal.png b/res/drawable-mdpi/all_apps_button_normal.png
index 227215b..2419f97 100644
--- a/res/drawable-mdpi/all_apps_button_normal.png
+++ b/res/drawable-mdpi/all_apps_button_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/all_apps_button_pressed.png b/res/drawable-mdpi/all_apps_button_pressed.png
index e243252..3e6c850 100644
--- a/res/drawable-mdpi/all_apps_button_pressed.png
+++ b/res/drawable-mdpi/all_apps_button_pressed.png
Binary files differ
diff --git a/res/drawable-mdpi/bg_appwidget_error.9.png b/res/drawable-mdpi/bg_appwidget_error.9.png
index 5077424..f222f94 100644
--- a/res/drawable-mdpi/bg_appwidget_error.9.png
+++ b/res/drawable-mdpi/bg_appwidget_error.9.png
Binary files differ
diff --git a/res/drawable-mdpi/box_launcher_bottom.9.png b/res/drawable-mdpi/box_launcher_bottom.9.png
index 1c99c50..e7dac0d 100644
--- a/res/drawable-mdpi/box_launcher_bottom.9.png
+++ b/res/drawable-mdpi/box_launcher_bottom.9.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 30b17b2..8adf2cf 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 033cd48..7a20c54 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 3ef394c..9e636f0 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/default_widget_preview.9.png b/res/drawable-mdpi/default_widget_preview.9.png
new file mode 100644
index 0000000..ed9c6ee
--- /dev/null
+++ b/res/drawable-mdpi/default_widget_preview.9.png
Binary files differ
diff --git a/res/drawable-mdpi/focused_application_background.9.png b/res/drawable-mdpi/focused_application_background.9.png
index 9d09b41..17ee6ea 100644
--- a/res/drawable-mdpi/focused_application_background.9.png
+++ b/res/drawable-mdpi/focused_application_background.9.png
Binary files differ
diff --git a/res/drawable-mdpi/gardening_crosshairs.png b/res/drawable-mdpi/gardening_crosshairs.png
new file mode 100644
index 0000000..d473044
--- /dev/null
+++ b/res/drawable-mdpi/gardening_crosshairs.png
Binary files differ
diff --git a/res/drawable-mdpi/home_button_focused.png b/res/drawable-mdpi/home_button_focused.png
index 701772b..4d62c1b 100644
--- a/res/drawable-mdpi/home_button_focused.png
+++ b/res/drawable-mdpi/home_button_focused.png
Binary files differ
diff --git a/res/drawable-mdpi/home_button_normal.png b/res/drawable-mdpi/home_button_normal.png
index cc7e3b0..37eccc0 100644
--- a/res/drawable-mdpi/home_button_normal.png
+++ b/res/drawable-mdpi/home_button_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/home_button_pressed.png b/res/drawable-mdpi/home_button_pressed.png
index ee8ddbe..4b77d6d 100644
--- a/res/drawable-mdpi/home_button_pressed.png
+++ b/res/drawable-mdpi/home_button_pressed.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_bg_center.9.png b/res/drawable-mdpi/hotseat_bg_center.9.png
index a9a05ba..c846d54 100644
--- a/res/drawable-mdpi/hotseat_bg_center.9.png
+++ b/res/drawable-mdpi/hotseat_bg_center.9.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_bg_left.9.png b/res/drawable-mdpi/hotseat_bg_left.9.png
index 35dfead..92d583f 100644
--- a/res/drawable-mdpi/hotseat_bg_left.9.png
+++ b/res/drawable-mdpi/hotseat_bg_left.9.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_bg_right.9.png b/res/drawable-mdpi/hotseat_bg_right.9.png
index 9adfa31..5181b00 100644
--- a/res/drawable-mdpi/hotseat_bg_right.9.png
+++ b/res/drawable-mdpi/hotseat_bg_right.9.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_browser_focused.png b/res/drawable-mdpi/hotseat_browser_focused.png
index 6d9d886..0ad0878 100644
--- a/res/drawable-mdpi/hotseat_browser_focused.png
+++ b/res/drawable-mdpi/hotseat_browser_focused.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_browser_normal.png b/res/drawable-mdpi/hotseat_browser_normal.png
index 0916b2c..52abe8c 100644
--- a/res/drawable-mdpi/hotseat_browser_normal.png
+++ b/res/drawable-mdpi/hotseat_browser_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_browser_pressed.png b/res/drawable-mdpi/hotseat_browser_pressed.png
index 5c6a137..e1d35d1 100644
--- a/res/drawable-mdpi/hotseat_browser_pressed.png
+++ b/res/drawable-mdpi/hotseat_browser_pressed.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_phone_focused.png b/res/drawable-mdpi/hotseat_phone_focused.png
index d55b277..3b2d361 100644
--- a/res/drawable-mdpi/hotseat_phone_focused.png
+++ b/res/drawable-mdpi/hotseat_phone_focused.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_phone_normal.png b/res/drawable-mdpi/hotseat_phone_normal.png
index 17ecda5..750960b 100644
--- a/res/drawable-mdpi/hotseat_phone_normal.png
+++ b/res/drawable-mdpi/hotseat_phone_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/hotseat_phone_pressed.png b/res/drawable-mdpi/hotseat_phone_pressed.png
index cc18ee3..8ad9d5a 100644
--- a/res/drawable-mdpi/hotseat_phone_pressed.png
+++ b/res/drawable-mdpi/hotseat_phone_pressed.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_1_focus.png b/res/drawable-mdpi/ic_home_arrows_1_focus.png
index 01817a4..c0c2720 100644
--- a/res/drawable-mdpi/ic_home_arrows_1_focus.png
+++ b/res/drawable-mdpi/ic_home_arrows_1_focus.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_1_focus_right.png b/res/drawable-mdpi/ic_home_arrows_1_focus_right.png
index a37d179..89eb552 100644
--- a/res/drawable-mdpi/ic_home_arrows_1_focus_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_1_focus_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_1_normal.png b/res/drawable-mdpi/ic_home_arrows_1_normal.png
index 1393607..c3b6e1d 100644
--- a/res/drawable-mdpi/ic_home_arrows_1_normal.png
+++ b/res/drawable-mdpi/ic_home_arrows_1_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_1_normal_right.png b/res/drawable-mdpi/ic_home_arrows_1_normal_right.png
index 1d5d587..705cf0f 100644
--- a/res/drawable-mdpi/ic_home_arrows_1_normal_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_1_normal_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_1_press.png b/res/drawable-mdpi/ic_home_arrows_1_press.png
index 1132b3c..b5d6e3e 100644
--- a/res/drawable-mdpi/ic_home_arrows_1_press.png
+++ b/res/drawable-mdpi/ic_home_arrows_1_press.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_1_press_right.png b/res/drawable-mdpi/ic_home_arrows_1_press_right.png
index 57f2133..694db41 100644
--- a/res/drawable-mdpi/ic_home_arrows_1_press_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_1_press_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_2_focus.png b/res/drawable-mdpi/ic_home_arrows_2_focus.png
index 0cf274d..fc64540 100644
--- a/res/drawable-mdpi/ic_home_arrows_2_focus.png
+++ b/res/drawable-mdpi/ic_home_arrows_2_focus.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_2_focus_right.png b/res/drawable-mdpi/ic_home_arrows_2_focus_right.png
index 16c008d..0e25d39 100644
--- a/res/drawable-mdpi/ic_home_arrows_2_focus_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_2_focus_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_2_normal.png b/res/drawable-mdpi/ic_home_arrows_2_normal.png
index 3c37560..712c57d 100644
--- a/res/drawable-mdpi/ic_home_arrows_2_normal.png
+++ b/res/drawable-mdpi/ic_home_arrows_2_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_2_normal_right.png b/res/drawable-mdpi/ic_home_arrows_2_normal_right.png
index 23172d8..5a4a26c 100644
--- a/res/drawable-mdpi/ic_home_arrows_2_normal_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_2_normal_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_2_press.png b/res/drawable-mdpi/ic_home_arrows_2_press.png
index 2ae042a..db8422d 100644
--- a/res/drawable-mdpi/ic_home_arrows_2_press.png
+++ b/res/drawable-mdpi/ic_home_arrows_2_press.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_2_press_right.png b/res/drawable-mdpi/ic_home_arrows_2_press_right.png
index 0fad08c..d55ea40 100644
--- a/res/drawable-mdpi/ic_home_arrows_2_press_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_2_press_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_3_focus.png b/res/drawable-mdpi/ic_home_arrows_3_focus.png
index 151b2f6..51f317c 100644
--- a/res/drawable-mdpi/ic_home_arrows_3_focus.png
+++ b/res/drawable-mdpi/ic_home_arrows_3_focus.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_3_focus_right.png b/res/drawable-mdpi/ic_home_arrows_3_focus_right.png
index 1072ee2..b61cf1c 100644
--- a/res/drawable-mdpi/ic_home_arrows_3_focus_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_3_focus_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_3_normal.png b/res/drawable-mdpi/ic_home_arrows_3_normal.png
index 92e6277..24f0c82 100644
--- a/res/drawable-mdpi/ic_home_arrows_3_normal.png
+++ b/res/drawable-mdpi/ic_home_arrows_3_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_3_normal_right.png b/res/drawable-mdpi/ic_home_arrows_3_normal_right.png
index 52c2ac7..8b41770 100644
--- a/res/drawable-mdpi/ic_home_arrows_3_normal_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_3_normal_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_3_press.png b/res/drawable-mdpi/ic_home_arrows_3_press.png
index 612b698..7ba3951 100644
--- a/res/drawable-mdpi/ic_home_arrows_3_press.png
+++ b/res/drawable-mdpi/ic_home_arrows_3_press.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_3_press_right.png b/res/drawable-mdpi/ic_home_arrows_3_press_right.png
index f8571f1..b5ceff4 100644
--- a/res/drawable-mdpi/ic_home_arrows_3_press_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_3_press_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_4_focus.png b/res/drawable-mdpi/ic_home_arrows_4_focus.png
index f3fffbe0..0265c6b 100644
--- a/res/drawable-mdpi/ic_home_arrows_4_focus.png
+++ b/res/drawable-mdpi/ic_home_arrows_4_focus.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_4_focus_right.png b/res/drawable-mdpi/ic_home_arrows_4_focus_right.png
index f01de46..e65ed85 100644
--- a/res/drawable-mdpi/ic_home_arrows_4_focus_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_4_focus_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_4_normal.png b/res/drawable-mdpi/ic_home_arrows_4_normal.png
index 2ad2745..f3a19a7 100644
--- a/res/drawable-mdpi/ic_home_arrows_4_normal.png
+++ b/res/drawable-mdpi/ic_home_arrows_4_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_4_normal_right.png b/res/drawable-mdpi/ic_home_arrows_4_normal_right.png
index e519de2..24ec6e7 100644
--- a/res/drawable-mdpi/ic_home_arrows_4_normal_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_4_normal_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_4_press.png b/res/drawable-mdpi/ic_home_arrows_4_press.png
index 9cbc554..9623df4 100644
--- a/res/drawable-mdpi/ic_home_arrows_4_press.png
+++ b/res/drawable-mdpi/ic_home_arrows_4_press.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_arrows_4_press_right.png b/res/drawable-mdpi/ic_home_arrows_4_press_right.png
index a60c8d5..8a577fa 100644
--- a/res/drawable-mdpi/ic_home_arrows_4_press_right.png
+++ b/res/drawable-mdpi/ic_home_arrows_4_press_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_application.png b/res/drawable-mdpi/ic_launcher_application.png
index 9777d11..18ea7a5 100644
--- a/res/drawable-mdpi/ic_launcher_application.png
+++ b/res/drawable-mdpi/ic_launcher_application.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_appwidget.png b/res/drawable-mdpi/ic_launcher_appwidget.png
index e9371d2..f369ccd 100644
--- a/res/drawable-mdpi/ic_launcher_appwidget.png
+++ b/res/drawable-mdpi/ic_launcher_appwidget.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder.png b/res/drawable-mdpi/ic_launcher_folder.png
index 14e0839..08b4aad 100644
--- a/res/drawable-mdpi/ic_launcher_folder.png
+++ b/res/drawable-mdpi/ic_launcher_folder.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_open.png b/res/drawable-mdpi/ic_launcher_folder_open.png
index 6a61ca6..b7640cb 100644
--- a/res/drawable-mdpi/ic_launcher_folder_open.png
+++ b/res/drawable-mdpi/ic_launcher_folder_open.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_home.png b/res/drawable-mdpi/ic_launcher_home.png
index 95a50e6..893d7c7 100644
--- a/res/drawable-mdpi/ic_launcher_home.png
+++ b/res/drawable-mdpi/ic_launcher_home.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut.png b/res/drawable-mdpi/ic_launcher_shortcut.png
index 05bc055..ba91360 100644
--- a/res/drawable-mdpi/ic_launcher_shortcut.png
+++ b/res/drawable-mdpi/ic_launcher_shortcut.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_wallpaper.png b/res/drawable-mdpi/ic_launcher_wallpaper.png
index 982fd88..7e7c6b8 100644
--- a/res/drawable-mdpi/ic_launcher_wallpaper.png
+++ b/res/drawable-mdpi/ic_launcher_wallpaper.png
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_left.9.png b/res/drawable-mdpi/page_hover_left.9.png
new file mode 100644
index 0000000..5d5e0c8
--- /dev/null
+++ b/res/drawable-mdpi/page_hover_left.9.png
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_right.9.png b/res/drawable-mdpi/page_hover_right.9.png
new file mode 100644
index 0000000..1545bfe
--- /dev/null
+++ b/res/drawable-mdpi/page_hover_right.9.png
Binary files differ
diff --git a/res/drawable-mdpi/pattern_carbon_fiber_dark.png b/res/drawable-mdpi/pattern_carbon_fiber_dark.png
deleted file mode 100644
index 44e050f..0000000
--- a/res/drawable-mdpi/pattern_carbon_fiber_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/placeholder_google.png b/res/drawable-mdpi/placeholder_google.png
deleted file mode 100644
index 4af30aa..0000000
--- a/res/drawable-mdpi/placeholder_google.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/pressed_application_background.9.png b/res/drawable-mdpi/pressed_application_background.9.png
similarity index 100%
rename from res/drawable/pressed_application_background.9.png
rename to res/drawable-mdpi/pressed_application_background.9.png
Binary files differ
diff --git a/res/drawable-mdpi/preview_bg.9.png b/res/drawable-mdpi/preview_bg.9.png
index 5647144..82c951d 100644
--- a/res/drawable-mdpi/preview_bg.9.png
+++ b/res/drawable-mdpi/preview_bg.9.png
Binary files differ
diff --git a/res/drawable-mdpi/preview_bg_focus.9.png b/res/drawable-mdpi/preview_bg_focus.9.png
index 31200fd..f64f6a0 100644
--- a/res/drawable-mdpi/preview_bg_focus.9.png
+++ b/res/drawable-mdpi/preview_bg_focus.9.png
Binary files differ
diff --git a/res/drawable-mdpi/preview_bg_press.9.png b/res/drawable-mdpi/preview_bg_press.9.png
index 9cb1266..151cab6 100644
--- a/res/drawable-mdpi/preview_bg_press.9.png
+++ b/res/drawable-mdpi/preview_bg_press.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_selected_focused_holo.9.png b/res/drawable-mdpi/tab_selected_focused_holo.9.png
new file mode 100644
index 0000000..9a33cd2
--- /dev/null
+++ b/res/drawable-mdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_selected_holo.9.png b/res/drawable-mdpi/tab_selected_holo.9.png
new file mode 100644
index 0000000..e029e57
--- /dev/null
+++ b/res/drawable-mdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_selected_pressed_focused_holo.9.png b/res/drawable-mdpi/tab_selected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..285116e
--- /dev/null
+++ b/res/drawable-mdpi/tab_selected_pressed_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_selected_pressed_holo.9.png b/res/drawable-mdpi/tab_selected_pressed_holo.9.png
new file mode 100644
index 0000000..dadefa7
--- /dev/null
+++ b/res/drawable-mdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_unselected_focused_holo.9.png b/res/drawable-mdpi/tab_unselected_focused_holo.9.png
new file mode 100644
index 0000000..032a992
--- /dev/null
+++ b/res/drawable-mdpi/tab_unselected_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_unselected_holo.9.png b/res/drawable-mdpi/tab_unselected_holo.9.png
new file mode 100644
index 0000000..e621983
--- /dev/null
+++ b/res/drawable-mdpi/tab_unselected_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_unselected_pressed_focused_holo.9.png b/res/drawable-mdpi/tab_unselected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..3845135
--- /dev/null
+++ b/res/drawable-mdpi/tab_unselected_pressed_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_unselected_pressed_holo.9.png b/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
new file mode 100644
index 0000000..23fd8c9
--- /dev/null
+++ b/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/trashcan.png b/res/drawable-mdpi/trashcan.png
index 4355164..f32bf27 100644
--- a/res/drawable-mdpi/trashcan.png
+++ b/res/drawable-mdpi/trashcan.png
Binary files differ
diff --git a/res/drawable-mdpi/trashcan_hover.png b/res/drawable-mdpi/trashcan_hover.png
index 96f4e51..bffa33f 100644
--- a/res/drawable-mdpi/trashcan_hover.png
+++ b/res/drawable-mdpi/trashcan_hover.png
Binary files differ
diff --git a/res/drawable-mdpi/wallpaper_nexuswallpaper1.png b/res/drawable-mdpi/wallpaper_nexuswallpaper1.png
new file mode 100644
index 0000000..20c74a1
--- /dev/null
+++ b/res/drawable-mdpi/wallpaper_nexuswallpaper1.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_divider.png b/res/drawable-mdpi/widget_divider.png
new file mode 100644
index 0000000..1b453c5
--- /dev/null
+++ b/res/drawable-mdpi/widget_divider.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/app_market_generic.png b/res/drawable-xlarge-hdpi/app_market_generic.png
new file mode 100644
index 0000000..2a2381f
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/app_market_generic.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/divider_launcher_holo.9.png b/res/drawable-xlarge-hdpi/divider_launcher_holo.9.png
new file mode 100644
index 0000000..0a1bd2a
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/divider_launcher_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/home_press.9.png b/res/drawable-xlarge-hdpi/home_press.9.png
new file mode 100644
index 0000000..743880b
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/home_press.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_large_blue.9.png b/res/drawable-xlarge-hdpi/homescreen_large_blue.9.png
new file mode 100644
index 0000000..6ce3d29
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/homescreen_large_blue.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_large_blue_strong.9.png b/res/drawable-xlarge-hdpi/homescreen_large_blue_strong.9.png
new file mode 100644
index 0000000..8110148
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/homescreen_large_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_large_green.9.png b/res/drawable-xlarge-hdpi/homescreen_large_green.9.png
new file mode 100644
index 0000000..4a6546e
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/homescreen_large_green.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_large_green_strong.9.png b/res/drawable-xlarge-hdpi/homescreen_large_green_strong.9.png
new file mode 100644
index 0000000..5ba9ebe
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/homescreen_large_green_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_small_blue.9.png b/res/drawable-xlarge-hdpi/homescreen_small_blue.9.png
new file mode 100644
index 0000000..db93b3c
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/homescreen_small_blue.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_small_blue_strong.9.png b/res/drawable-xlarge-hdpi/homescreen_small_blue_strong.9.png
new file mode 100644
index 0000000..32bd857
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/homescreen_small_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_small_green.9.png b/res/drawable-xlarge-hdpi/homescreen_small_green.9.png
new file mode 100644
index 0000000..00baae9
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/homescreen_small_green.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_small_green_strong.9.png b/res/drawable-xlarge-hdpi/homescreen_small_green_strong.9.png
new file mode 100644
index 0000000..e1e64c5
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/homescreen_small_green_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_all_apps_holo_dark.png b/res/drawable-xlarge-hdpi/ic_home_all_apps_holo_dark.png
new file mode 100644
index 0000000..3c7930f
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/ic_home_all_apps_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_configure_holo_dark.png b/res/drawable-xlarge-hdpi/ic_home_configure_holo_dark.png
new file mode 100644
index 0000000..6c94a31
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/ic_home_configure_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_delete_holo_dark.png b/res/drawable-xlarge-hdpi/ic_home_delete_holo_dark.png
new file mode 100644
index 0000000..9d64278
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/ic_home_delete_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_delete_hover_holo_dark.png b/res/drawable-xlarge-hdpi/ic_home_delete_hover_holo_dark.png
new file mode 100644
index 0000000..60d5b15
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/ic_home_delete_hover_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_info_holo_dark.png b/res/drawable-xlarge-hdpi/ic_home_info_holo_dark.png
new file mode 100644
index 0000000..02df4e1
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/ic_home_info_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_no_applications.png b/res/drawable-xlarge-hdpi/ic_no_applications.png
new file mode 100644
index 0000000..933d091
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/ic_no_applications.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/search_button_normal.png b/res/drawable-xlarge-hdpi/search_button_normal.png
new file mode 100644
index 0000000..b1df556
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/search_button_normal.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/search_button_pressed.png b/res/drawable-xlarge-hdpi/search_button_pressed.png
new file mode 100644
index 0000000..1013383
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/search_button_pressed.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/tab_selected_focused_holo.9.png b/res/drawable-xlarge-hdpi/tab_selected_focused_holo.9.png
new file mode 100644
index 0000000..1ba35d5
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/tab_selected_holo.9.png b/res/drawable-xlarge-hdpi/tab_selected_holo.9.png
new file mode 100644
index 0000000..ef913cc
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/tab_selected_pressed_focused_holo.9.png b/res/drawable-xlarge-hdpi/tab_selected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..d7e9688
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/tab_selected_pressed_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/tab_selected_pressed_holo.9.png b/res/drawable-xlarge-hdpi/tab_selected_pressed_holo.9.png
new file mode 100644
index 0000000..b8b1fcf
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/textfield_home_end.9.png b/res/drawable-xlarge-hdpi/textfield_home_end.9.png
new file mode 100644
index 0000000..4e79920
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/textfield_home_end.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/textfield_home_start.9.png b/res/drawable-xlarge-hdpi/textfield_home_start.9.png
new file mode 100644
index 0000000..a338c69
--- /dev/null
+++ b/res/drawable-xlarge-hdpi/textfield_home_start.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/app_market_generic.png b/res/drawable-xlarge-mdpi/app_market_generic.png
new file mode 100644
index 0000000..c093e24
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/app_market_generic.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/divider_launcher_holo.9.png b/res/drawable-xlarge-mdpi/divider_launcher_holo.9.png
new file mode 100644
index 0000000..6d101f4
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/divider_launcher_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/home_press.9.png b/res/drawable-xlarge-mdpi/home_press.9.png
new file mode 100644
index 0000000..ff841c3
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/home_press.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_large_blue.9.png b/res/drawable-xlarge-mdpi/homescreen_large_blue.9.png
new file mode 100644
index 0000000..5e7e61f
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/homescreen_large_blue.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_large_blue_strong.9.png b/res/drawable-xlarge-mdpi/homescreen_large_blue_strong.9.png
new file mode 100644
index 0000000..f4913e5
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/homescreen_large_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_large_green.9.png b/res/drawable-xlarge-mdpi/homescreen_large_green.9.png
new file mode 100644
index 0000000..2f83bac
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/homescreen_large_green.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_large_green_strong.9.png b/res/drawable-xlarge-mdpi/homescreen_large_green_strong.9.png
new file mode 100644
index 0000000..1e14502
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/homescreen_large_green_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_small_blue.9.png b/res/drawable-xlarge-mdpi/homescreen_small_blue.9.png
new file mode 100644
index 0000000..28bc33b
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/homescreen_small_blue.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_small_blue_strong.9.png b/res/drawable-xlarge-mdpi/homescreen_small_blue_strong.9.png
new file mode 100644
index 0000000..f286de9
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/homescreen_small_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_small_green.9.png b/res/drawable-xlarge-mdpi/homescreen_small_green.9.png
new file mode 100644
index 0000000..58698ea
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/homescreen_small_green.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_small_green_strong.9.png b/res/drawable-xlarge-mdpi/homescreen_small_green_strong.9.png
new file mode 100644
index 0000000..9773085
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/homescreen_small_green_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_add_holo_dark.png b/res/drawable-xlarge-mdpi/ic_home_add_holo_dark.png
new file mode 100644
index 0000000..d3ab3ad
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/ic_home_add_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_all_apps_holo_dark.png b/res/drawable-xlarge-mdpi/ic_home_all_apps_holo_dark.png
new file mode 100644
index 0000000..0261d0d
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/ic_home_all_apps_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_configure_holo_dark.png b/res/drawable-xlarge-mdpi/ic_home_configure_holo_dark.png
new file mode 100644
index 0000000..8a99273
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/ic_home_configure_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_delete_holo_dark.png b/res/drawable-xlarge-mdpi/ic_home_delete_holo_dark.png
new file mode 100644
index 0000000..647fd80
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/ic_home_delete_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_delete_hover_holo_dark.png b/res/drawable-xlarge-mdpi/ic_home_delete_hover_holo_dark.png
new file mode 100644
index 0000000..06b62e2
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/ic_home_delete_hover_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_info_holo_dark.png b/res/drawable-xlarge-mdpi/ic_home_info_holo_dark.png
new file mode 100644
index 0000000..c34f443
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/ic_home_info_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_no_applications.png b/res/drawable-xlarge-mdpi/ic_no_applications.png
new file mode 100644
index 0000000..a4f695a
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/ic_no_applications.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_voice_search.png b/res/drawable-xlarge-mdpi/ic_voice_search.png
new file mode 100644
index 0000000..a2fe874
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/ic_voice_search.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/search_button_normal.png b/res/drawable-xlarge-mdpi/search_button_normal.png
new file mode 100644
index 0000000..b172074
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/search_button_normal.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/search_button_pressed.png b/res/drawable-xlarge-mdpi/search_button_pressed.png
new file mode 100644
index 0000000..c2926c8
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/search_button_pressed.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/tab_selected_focused_holo.9.png b/res/drawable-xlarge-mdpi/tab_selected_focused_holo.9.png
new file mode 100644
index 0000000..782ae35
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/tab_selected_holo.9.png b/res/drawable-xlarge-mdpi/tab_selected_holo.9.png
new file mode 100644
index 0000000..255d072
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/tab_selected_pressed_focused_holo.9.png b/res/drawable-xlarge-mdpi/tab_selected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..10152bb
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/tab_selected_pressed_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/tab_selected_pressed_holo.9.png b/res/drawable-xlarge-mdpi/tab_selected_pressed_holo.9.png
new file mode 100644
index 0000000..822ed51
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/textfield_home_end.9.png b/res/drawable-xlarge-mdpi/textfield_home_end.9.png
new file mode 100644
index 0000000..753514f
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/textfield_home_end.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/textfield_home_start.9.png b/res/drawable-xlarge-mdpi/textfield_home_start.9.png
new file mode 100644
index 0000000..11ee7ca
--- /dev/null
+++ b/res/drawable-xlarge-mdpi/textfield_home_start.9.png
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/all_apps_bg_gradient.9.png b/res/drawable-xlarge-nodpi/all_apps_bg_gradient.9.png
new file mode 100644
index 0000000..3f4b5b5
--- /dev/null
+++ b/res/drawable-xlarge-nodpi/all_apps_bg_gradient.9.png
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/city_wallpaper.jpg b/res/drawable-xlarge-nodpi/city_wallpaper.jpg
new file mode 100644
index 0000000..8d3035e
--- /dev/null
+++ b/res/drawable-xlarge-nodpi/city_wallpaper.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/city_wallpaper_small.png b/res/drawable-xlarge-nodpi/city_wallpaper_small.png
new file mode 100644
index 0000000..36d6d74
--- /dev/null
+++ b/res/drawable-xlarge-nodpi/city_wallpaper_small.png
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/customize_bg_gradient.png b/res/drawable-xlarge-nodpi/customize_bg_gradient.png
new file mode 100644
index 0000000..89df7a9
--- /dev/null
+++ b/res/drawable-xlarge-nodpi/customize_bg_gradient.png
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/glow_wallpaper.png b/res/drawable-xlarge-nodpi/glow_wallpaper.png
new file mode 100644
index 0000000..eb29449
--- /dev/null
+++ b/res/drawable-xlarge-nodpi/glow_wallpaper.png
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/glow_wallpaper_small.png b/res/drawable-xlarge-nodpi/glow_wallpaper_small.png
new file mode 100644
index 0000000..f83fc60
--- /dev/null
+++ b/res/drawable-xlarge-nodpi/glow_wallpaper_small.png
Binary files differ
diff --git a/res/drawable-xlarge/button_bg.xml b/res/drawable-xlarge/button_bg.xml
new file mode 100644
index 0000000..9e6e1ff
--- /dev/null
+++ b/res/drawable-xlarge/button_bg.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<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" />
+</selector>
diff --git a/res/drawable-xlarge/delete_zone_selector.xml b/res/drawable-xlarge/delete_zone_selector.xml
new file mode 100644
index 0000000..e2b37f4
--- /dev/null
+++ b/res/drawable-xlarge/delete_zone_selector.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <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-xlarge/search_button_generic.xml b/res/drawable-xlarge/search_button_generic.xml
new file mode 100644
index 0000000..8f18e67
--- /dev/null
+++ b/res/drawable-xlarge/search_button_generic.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/search_button_pressed" />
+ <item android:drawable="@drawable/search_button_normal" />
+</selector>
diff --git a/res/drawable/shortcut_selector.xml b/res/drawable/shortcut_selector.xml
deleted file mode 100644
index 884bccf..0000000
--- a/res/drawable/shortcut_selector.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2007, 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.
-*/
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true" android:drawable="@drawable/pressed_application_background" />
- <item android:state_window_focused="true" android:state_focused="true" android:drawable="@drawable/focused_application_background" />
- <item android:state_window_focused="false" android:state_focused="true" android:drawable="@android:color/transparent" />
-</selector>
diff --git a/res/drawable/tab_widget_indicator_selector.xml b/res/drawable/tab_widget_indicator_selector.xml
new file mode 100644
index 0000000..ff92b40
--- /dev/null
+++ b/res/drawable/tab_widget_indicator_selector.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Non focused states -->
+ <item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/tab_unselected_holo" />
+ <item android:state_focused="false" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/tab_selected_holo" />
+
+ <!-- Focused states -->
+ <item android:state_focused="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/tab_unselected_focused_holo" />
+ <item android:state_focused="true" android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/tab_selected_focused_holo" />
+
+ <!-- Pressed -->
+ <!-- Non focused states -->
+ <item android:state_focused="false" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/tab_unselected_pressed_holo" />
+ <item android:state_focused="false" android:state_selected="true" android:state_pressed="true" android:drawable="@drawable/tab_selected_pressed_holo" />
+
+ <!-- Focused states -->
+ <item android:state_focused="true" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/tab_unselected_pressed_focused_holo" />
+ <item android:state_focused="true" android:state_selected="true" android:state_pressed="true" android:drawable="@drawable/tab_selected_pressed_focused_holo" />
+</selector>
diff --git a/res/drawable/wallpaper_picker_preview.png b/res/drawable/wallpaper_picker_preview.png
new file mode 100644
index 0000000..926a99c
--- /dev/null
+++ b/res/drawable/wallpaper_picker_preview.png
Binary files differ
diff --git a/res/layout-land/all_apps_2d.xml b/res/layout-land/all_apps_2d.xml
index a253b93..b7fcd45 100644
--- a/res/layout-land/all_apps_2d.xml
+++ b/res/layout-land/all_apps_2d.xml
@@ -22,7 +22,7 @@
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"
diff --git a/res/layout-land/application.xml b/res/layout-land/application.xml
index 6de5658..6e8c31e 100644
--- a/res/layout-land/application.xml
+++ b/res/layout-land/application.xml
@@ -15,4 +15,4 @@
-->
<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/WorkspaceIcon.Landscape" />
+ style="@style/WorkspaceIcon.Landscape" />
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 1f13f1f..6e797f8 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -24,14 +24,16 @@
<include layout="@layout/all_apps" />
- <!-- The workspace contains 3 screens of cells -->
+ <!-- The workspace contains 5 screens of cells -->
<com.android.launcher2.Workspace
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="horizontal"
android:fadeScrollbars="true"
- launcher:defaultScreen="2">
+ launcher:defaultScreen="2"
+ launcher:cellCountX="4"
+ launcher:cellCountY="4">
<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
<include android:id="@+id/cell2" layout="@layout/workspace_screen" />
@@ -84,7 +86,7 @@
android:layout_gravity="right|center_vertical"
android:scaleType="center"
- android:src="@drawable/delete_zone_selector"
+ android:drawableLeft="@drawable/delete_zone_selector"
android:visibility="invisible"
launcher:direction="vertical"
/>
diff --git a/res/layout-land/workspace_screen.xml b/res/layout-land/workspace_screen.xml
index 315e68b..9323f58 100644
--- a/res/layout-land/workspace_screen.xml
+++ b/res/layout-land/workspace_screen.xml
@@ -24,9 +24,7 @@
launcher:cellWidth="@dimen/workspace_cell_width"
launcher:cellHeight="@dimen/workspace_cell_height"
- launcher:longAxisStartPadding="65dip"
- launcher:longAxisEndPadding="65dip"
- launcher:shortAxisStartPadding="0dip"
- launcher:shortAxisEndPadding="0dip"
- launcher:shortAxisCells="4"
- launcher:longAxisCells="4" />
+ launcher:xAxisStartPadding="65dip"
+ launcher:xAxisEndPadding="65dip"
+ launcher:yAxisStartPadding="0dip"
+ launcher:yAxisEndPadding="0dip"/>
diff --git a/res/layout-port/all_apps_2d.xml b/res/layout-port/all_apps_2d.xml
index 0607d62..081cba2 100644
--- a/res/layout-port/all_apps_2d.xml
+++ b/res/layout-port/all_apps_2d.xml
@@ -22,7 +22,7 @@
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"
diff --git a/res/layout-port/application.xml b/res/layout-port/application.xml
index f904a66..32c1510 100644
--- a/res/layout-port/application.xml
+++ b/res/layout-port/application.xml
@@ -4,9 +4,9 @@
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.
@@ -15,4 +15,4 @@
-->
<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/WorkspaceIcon.Portrait" />
+ style="@style/WorkspaceIcon.Portrait" />
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 8dc5092..b7c61d8 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -24,12 +24,14 @@
<include layout="@layout/all_apps" />
- <!-- The workspace contains 3 screens of cells -->
+ <!-- The workspace contains 5 screens of cells -->
<com.android.launcher2.Workspace
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
- launcher:defaultScreen="2">
+ launcher:defaultScreen="2"
+ launcher:cellCountX="4"
+ launcher:cellCountY="4">
<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
<include android:id="@+id/cell2" layout="@layout/workspace_screen" />
@@ -77,7 +79,7 @@
android:layout_gravity="bottom|center_horizontal"
android:scaleType="center"
- android:src="@drawable/delete_zone_selector"
+ android:drawableLeft="@drawable/delete_zone_selector"
android:visibility="invisible"
launcher:direction="horizontal"
/>
diff --git a/res/layout-port/workspace_screen.xml b/res/layout-port/workspace_screen.xml
index bd4a4bd..f400c40 100644
--- a/res/layout-port/workspace_screen.xml
+++ b/res/layout-port/workspace_screen.xml
@@ -24,9 +24,7 @@
launcher:cellWidth="@dimen/workspace_cell_width"
launcher:cellHeight="@dimen/workspace_cell_height"
- launcher:longAxisStartPadding="8dip"
- launcher:longAxisEndPadding="78dip"
- launcher:shortAxisStartPadding="0dip"
- launcher:shortAxisEndPadding="0dip"
- launcher:shortAxisCells="4"
- launcher:longAxisCells="4" />
+ launcher:yAxisStartPadding="8dip"
+ launcher:yAxisEndPadding="@dimen/button_bar_height"
+ launcher:xAxisStartPadding="0dip"
+ launcher:xAxisEndPadding="0dip" />
diff --git a/res/layout-xlarge-land/all_apps_tabbed.xml b/res/layout-xlarge-land/all_apps_tabbed.xml
new file mode 100644
index 0000000..fbe98b0
--- /dev/null
+++ b/res/layout-xlarge-land/all_apps_tabbed.xml
@@ -0,0 +1,94 @@
+<?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.
+-->
+<com.android.launcher2.AllAppsTabbed
+ 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">
+ <RelativeLayout
+ android:layout_width="952dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/tab_unselected_holo">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:tabStripEnabled="false" />
+ <FrameLayout
+ android:id="@+id/market_info_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true">
+ <com.android.launcher2.ApplicationInfoDropTarget
+ android:id="@+id/all_apps_info_target"
+ android:drawableRight="@drawable/ic_home_info_holo_dark"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="invisible"/>
+ <ImageView
+ android:id="@+id/market_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:onClick="onClickAppMarketButton"/>
+ </FrameLayout>
+ <com.android.launcher2.DeleteZone
+ android:id="@+id/all_apps_delete_zone"
+ android:text="@string/delete_zone_label_all_apps"
+ android:drawablePadding="@dimen/all_apps_drawable_padding"
+ android:drawableLeft="@drawable/delete_zone_selector"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/market_info_frame"
+ android:layout_centerVertical="true"
+ android:visibility="invisible"
+ android:paddingRight="22dp"
+ launcher:direction="horizontal"
+
+ android:gravity="center_horizontal|center_vertical"
+ android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
+ android:textSize="18sp"
+ android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
+ android:shadowDx="0.0"
+ android:shadowDy="0.0"
+ android:shadowRadius="2.0" />
+ </RelativeLayout>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <com.android.launcher2.AllAppsPagedView
+ android:id="@+id/all_apps_paged_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ launcher:cellCountX="7"
+ launcher:cellCountY="5"
+ launcher:pageLayoutWidthGap="36dp"
+ launcher:pageLayoutHeightGap="6dp"
+ launcher:pageLayoutPaddingTop="20dp"
+ launcher:pageLayoutPaddingBottom="15dp"
+ launcher:pageLayoutPaddingLeft="40dp"
+ launcher:pageLayoutPaddingRight="40dp">
+ </com.android.launcher2.AllAppsPagedView>
+ </FrameLayout>
+ </LinearLayout>
+</com.android.launcher2.AllAppsTabbed>
diff --git a/res/layout-xlarge-land/application.xml b/res/layout-xlarge-land/application.xml
new file mode 100644
index 0000000..2598e5a
--- /dev/null
+++ b/res/layout-xlarge-land/application.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+
+<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/WorkspaceIcon.Landscape" />
diff --git a/res/layout-xlarge-land/customization_drawer.xml b/res/layout-xlarge-land/customization_drawer.xml
new file mode 100644
index 0000000..50e7b66
--- /dev/null
+++ b/res/layout-xlarge-land/customization_drawer.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<com.android.launcher2.CustomizePagedView
+ 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"
+ launcher:wallpaperCellSpanX="3"
+ launcher:wallpaperCellCountX="12"
+ launcher:widgetCellCountX="14"
+ launcher:cellCountX="8"
+ launcher:cellCountY="3"
+ launcher:pageLayoutWidthGap="32dp"
+ launcher:pageLayoutHeightGap="12dp"
+ launcher:pageLayoutPaddingTop="40dp"
+ launcher:pageLayoutPaddingBottom="25dp"
+ launcher:pageLayoutPaddingLeft="20dp"
+ launcher:pageLayoutPaddingRight="20dp" />
\ No newline at end of file
diff --git a/res/layout-xlarge-land/launcher.xml b/res/layout-xlarge-land/launcher.xml
new file mode 100644
index 0000000..93d19dc
--- /dev/null
+++ b/res/layout-xlarge-land/launcher.xml
@@ -0,0 +1,218 @@
+<?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.
+-->
+
+<com.android.launcher2.DragLayer
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+ android:id="@+id/drag_layer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- The workspace contains 5 screens of cells -->
+ <com.android.launcher2.Workspace
+ android:id="@+id/workspace"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="?android:attr/actionBarSize"
+ android:paddingBottom="10dp"
+ launcher:defaultScreen="2"
+ launcher:cellCountX="8"
+ launcher:cellCountY="7"
+ launcher:pageSpacing="50dp">
+
+ <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
+ <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
+ <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
+ <include android:id="@+id/cell4" layout="@layout/workspace_screen" />
+ <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" />
+
+ <RelativeLayout
+ android:id="@+id/all_apps_button_cluster"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:layout_gravity="top">
+
+ <LinearLayout android:id="@+id/search_button_cluster"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:gravity="bottom"
+ >
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="16dp"
+ android:background="@drawable/textfield_home_start"
+ android:orientation="horizontal">
+ <!-- Global search icon -->
+ <ImageView
+ android:id="@+id/search_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:paddingLeft="8dp"
+ android:paddingRight="32dp"
+ android:paddingTop="12dp"
+ android:src="@drawable/search_button_generic"
+ android:background="@drawable/button_bg"
+ android:onClick="onClickSearchButton"
+ android:focusable="true"
+ android:clickable="true"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="@drawable/textfield_home_end"
+ android:orientation="horizontal">
+ <!-- Voice search icon -->
+ <ImageView
+ android:id="@+id/voice_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingTop="12dp"
+ android:src="@drawable/ic_voice_search"
+ android:background="@drawable/button_bg"
+ android:onClick="onClickVoiceButton"
+ android:focusable="true"
+ android:clickable="true"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <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:onClick="onClickConfigureButton"
+ 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="@dimen/toolbar_divider_height"
+ android:layout_toLeftOf="@id/configure_button"
+ android:paddingTop="@dimen/toolbar_button_vertical_padding"
+ android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+
+ android:onClick="onClickAllAppsButton"
+ android:focusable="true"
+ android:clickable="true" />
+ <TextView
+ android:id="@+id/all_apps_button"
+ android:text="@string/all_apps_button_label"
+ android:drawablePadding="@dimen/all_apps_drawable_padding"
+ 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: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:gravity="center_horizontal|center_vertical"
+ android:textColor="#CCFFFFFF"
+ android:textSize="18sp"
+
+ android:shadowColor="#DA000000"
+ android:shadowDx="0.0"
+ android:shadowDy="0.0"
+ android:shadowRadius="2.5"
+
+ android:onClick="onClickAllAppsButton"
+ android:focusable="true"
+ android:clickable="true" />
+ <ImageView
+ android:id="@+id/divider_during_drag"
+ android:src="@drawable/divider_launcher_holo"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/toolbar_divider_height"
+ android:layout_toLeftOf="@id/configure_button"
+ android:paddingTop="@dimen/toolbar_button_vertical_padding"
+ android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+ android:visibility="gone"/>
+ <com.android.launcher2.DeleteZone
+ android:id="@+id/delete_zone"
+ android:text="@string/delete_zone_label_workspace"
+ android:drawablePadding="@dimen/all_apps_drawable_padding"
+ android:drawableLeft="@drawable/delete_zone_selector"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ 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:gravity="center_horizontal|center_vertical"
+ android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
+ android:textSize="18sp"
+ 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:visibility="gone"
+ launcher:direction="horizontal" />
+ </RelativeLayout>
+
+ <TabHost
+ android:id="@+id/customization_drawer"
+ android:layout_width="match_parent"
+ android:layout_height="480dp"
+ android:layout_gravity="bottom">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="952dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/tab_unselected_holo"
+ android:tabStripEnabled="false" />
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+</com.android.launcher2.DragLayer>
diff --git a/res/layout-xlarge-land/workspace_screen.xml b/res/layout-xlarge-land/workspace_screen.xml
new file mode 100644
index 0000000..e983b79
--- /dev/null
+++ b/res/layout-xlarge-land/workspace_screen.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<com.android.launcher2.CellLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:hapticFeedbackEnabled="false"
+
+ launcher:cellWidth="@dimen/workspace_cell_width"
+ launcher:cellHeight="@dimen/workspace_cell_height"
+ launcher:widthGap="@dimen/workspace_width_gap"
+ launcher:heightGap="@dimen/workspace_height_gap"
+ launcher:yAxisStartPadding="15dip"
+ launcher:yAxisEndPadding="15dip"
+ launcher:xAxisStartPadding="25dip"
+ launcher:xAxisEndPadding="25dip" />
diff --git a/res/layout-xlarge-port/all_apps_tabbed.xml b/res/layout-xlarge-port/all_apps_tabbed.xml
new file mode 100644
index 0000000..b90041c
--- /dev/null
+++ b/res/layout-xlarge-port/all_apps_tabbed.xml
@@ -0,0 +1,94 @@
+<?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.
+-->
+<com.android.launcher2.AllAppsTabbed
+ 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">
+ <RelativeLayout
+ android:layout_width="700dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/tab_unselected_holo">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:tabStripEnabled="false" />
+ <FrameLayout
+ android:id="@+id/market_info_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true">
+ <com.android.launcher2.ApplicationInfoDropTarget
+ android:id="@+id/all_apps_info_target"
+ android:drawableRight="@drawable/ic_home_info_holo_dark"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="invisible"/>
+ <ImageView
+ android:id="@+id/market_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:onClick="onClickAppMarketButton"/>
+ </FrameLayout>
+ <com.android.launcher2.DeleteZone
+ android:id="@+id/all_apps_delete_zone"
+ android:text="@string/delete_zone_label_all_apps"
+ android:drawablePadding="@dimen/all_apps_drawable_padding"
+ android:drawableLeft="@drawable/delete_zone_selector"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/market_info_frame"
+ android:layout_centerVertical="true"
+ android:visibility="invisible"
+ android:paddingRight="22dp"
+ launcher:direction="horizontal"
+
+ android:gravity="center_horizontal|center_vertical"
+ android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
+ android:textSize="18sp"
+ android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
+ android:shadowDx="0.0"
+ android:shadowDy="0.0"
+ android:shadowRadius="2.0" />
+ </RelativeLayout>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <com.android.launcher2.AllAppsPagedView
+ android:id="@+id/all_apps_paged_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ launcher:cellCountX="5"
+ launcher:cellCountY="7"
+ launcher:pageLayoutWidthGap="36dp"
+ launcher:pageLayoutHeightGap="36dp"
+ launcher:pageLayoutPaddingTop="25dp"
+ launcher:pageLayoutPaddingBottom="10dp"
+ launcher:pageLayoutPaddingLeft="20dp"
+ launcher:pageLayoutPaddingRight="20dp">
+ </com.android.launcher2.AllAppsPagedView>
+ </FrameLayout>
+ </LinearLayout>
+</com.android.launcher2.AllAppsTabbed>
diff --git a/res/layout-xlarge-port/application.xml b/res/layout-xlarge-port/application.xml
new file mode 100644
index 0000000..af7a8a4
--- /dev/null
+++ b/res/layout-xlarge-port/application.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+
+<com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/WorkspaceIcon.Portrait" />
diff --git a/res/layout-xlarge-port/customization_drawer.xml b/res/layout-xlarge-port/customization_drawer.xml
new file mode 100644
index 0000000..a1bc7cc
--- /dev/null
+++ b/res/layout-xlarge-port/customization_drawer.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<com.android.launcher2.CustomizePagedView
+ 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"
+ launcher:wallpaperCellSpanX="3"
+ launcher:wallpaperCellCountX="9"
+ launcher:widgetCellCountX="10"
+ launcher:cellCountX="5"
+ launcher:cellCountY="3"
+ launcher:pageLayoutWidthGap="36dp"
+ launcher:pageLayoutHeightGap="12dp"
+ launcher:pageLayoutPaddingTop="40dp"
+ launcher:pageLayoutPaddingBottom="25dp"
+ launcher:pageLayoutPaddingLeft="20dp"
+ launcher:pageLayoutPaddingRight="20dp" />
diff --git a/res/layout-xlarge-port/launcher.xml b/res/layout-xlarge-port/launcher.xml
new file mode 100644
index 0000000..6ad5d9c
--- /dev/null
+++ b/res/layout-xlarge-port/launcher.xml
@@ -0,0 +1,215 @@
+<?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.
+-->
+
+<com.android.launcher2.DragLayer
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+ android:id="@+id/drag_layer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- The workspace contains 5 screens of cells -->
+ <com.android.launcher2.Workspace
+ android:id="@+id/workspace"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="?android:attr/actionBarSize"
+ android:paddingBottom="10dp"
+ launcher:defaultScreen="2"
+ launcher:cellCountX="8"
+ launcher:cellCountY="7"
+ launcher:pageSpacing="64dp">
+
+ <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
+ <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
+ <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
+ <include android:id="@+id/cell4" layout="@layout/workspace_screen" />
+ <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"/>
+
+ <RelativeLayout
+ android:id="@+id/all_apps_button_cluster"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:layout_gravity="top">
+
+ <LinearLayout android:id="@+id/search_button_cluster"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:gravity="bottom"
+ >
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="16dp"
+ android:background="@drawable/textfield_home_start"
+ android:orientation="horizontal">
+ <!-- Global search icon -->
+ <ImageView
+ android:id="@+id/search_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:paddingLeft="8dp"
+ android:paddingRight="32dp"
+ android:paddingTop="12dp"
+ android:src="@drawable/search_button_generic"
+ android:background="@drawable/button_bg"
+ android:onClick="onClickSearchButton"
+ android:focusable="true"
+ android:clickable="true"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="@drawable/textfield_home_end"
+ android:orientation="horizontal">
+ <!-- Voice search icon -->
+ <ImageView
+ android:id="@+id/voice_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingTop="12dp"
+ android:src="@drawable/ic_voice_search"
+ android:background="@drawable/button_bg"
+ android:onClick="onClickVoiceButton"
+ android:focusable="true"
+ android:clickable="true"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <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:onClick="onClickConfigureButton"
+ 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="@dimen/toolbar_divider_height"
+ android:layout_toLeftOf="@id/configure_button"
+ android:paddingTop="@dimen/toolbar_button_vertical_padding"
+ android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+
+ android:onClick="onClickAllAppsButton"
+ android:focusable="true"
+ android:clickable="true" />
+ <TextView
+ android:id="@+id/all_apps_button"
+ android:text="@string/all_apps_button_label"
+ android:drawablePadding="@dimen/all_apps_drawable_padding"
+ 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: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:gravity="center_horizontal|center_vertical"
+ android:textColor="#CCFFFFFF"
+ android:textSize="18sp"
+
+ android:shadowColor="#DA000000"
+ android:shadowDx="0.0"
+ android:shadowDy="0.0"
+ android:shadowRadius="2.5"
+
+ android:onClick="onClickAllAppsButton"
+ android:focusable="true"
+ android:clickable="true" />
+ <ImageView
+ android:id="@+id/divider_during_drag"
+ android:src="@drawable/divider_launcher_holo"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/toolbar_divider_height"
+ android:layout_toLeftOf="@id/configure_button"
+ android:paddingTop="@dimen/toolbar_button_vertical_padding"
+ android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+ android:visibility="gone"/>
+ <com.android.launcher2.DeleteZone
+ android:id="@+id/delete_zone"
+ android:text="@string/delete_zone_label_workspace"
+ android:drawablePadding="@dimen/all_apps_drawable_padding"
+ android:drawableLeft="@drawable/delete_zone_selector"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ 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:gravity="center_horizontal|center_vertical"
+ android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
+ android:textSize="18sp"
+ 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:visibility="gone"
+ launcher:direction="horizontal" />
+ </RelativeLayout>
+
+ <TabHost
+ android:id="@+id/customization_drawer"
+ android:layout_width="match_parent"
+ android:layout_height="800dp"
+ android:layout_gravity="bottom">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="700dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/tab_unselected_holo"
+ android:tabStripEnabled="false" />
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="650dp">
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+</com.android.launcher2.DragLayer>
diff --git a/res/layout-xlarge-port/workspace_screen.xml b/res/layout-xlarge-port/workspace_screen.xml
new file mode 100644
index 0000000..406441d
--- /dev/null
+++ b/res/layout-xlarge-port/workspace_screen.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<com.android.launcher2.CellLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:hapticFeedbackEnabled="false"
+
+ launcher:cellWidth="@dimen/workspace_cell_width"
+ launcher:cellHeight="@dimen/workspace_cell_height"
+ launcher:widthGap="@dimen/workspace_width_gap"
+ launcher:heightGap="@dimen/workspace_height_gap"
+ launcher:yAxisStartPadding="25dip"
+ launcher:yAxisEndPadding="25dip"
+ launcher:xAxisStartPadding="15dip"
+ launcher:xAxisEndPadding="15dip"/>
diff --git a/res/layout-xlarge/all_apps_no_items_placeholder.xml b/res/layout-xlarge/all_apps_no_items_placeholder.xml
new file mode 100644
index 0000000..247870c
--- /dev/null
+++ b/res/layout-xlarge/all_apps_no_items_placeholder.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+
+ android:id="@+id/no_items_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:paddingTop="2dip"
+
+ android:textColor="#FFFFFFFF"
+ android:textSize="15sp"
+ android:shadowColor="#FF000000"
+ android:shadowDx="0.0"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0"
+ android:drawablePadding="0dip"
+
+ android:maxLines="2"
+ android:fadingEdge="horizontal" />
diff --git a/res/layout-xlarge/all_apps_paged_view_application.xml b/res/layout-xlarge/all_apps_paged_view_application.xml
new file mode 100644
index 0000000..e5f07bf
--- /dev/null
+++ b/res/layout-xlarge/all_apps_paged_view_application.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<com.android.launcher2.PagedViewIcon
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+ launcher:blurColor="#FF6B8CF0"
+ launcher:outlineColor="#FF8CD2FF"
+
+ android:id="@+id/application_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+
+ style="@style/WorkspaceIcon.AllApps" />
diff --git a/res/layout-xlarge/customize_paged_view_item.xml b/res/layout-xlarge/customize_paged_view_item.xml
new file mode 100644
index 0000000..b2e5f08
--- /dev/null
+++ b/res/layout-xlarge/customize_paged_view_item.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<com.android.launcher2.PagedViewIcon
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+
+ launcher:blurColor="#FF6B8CF0"
+ launcher:outlineColor="#FF8CD2FF"
+
+ android:id="@+id/customize_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+
+ style="@style/WorkspaceIcon.Landscape" />
diff --git a/res/layout-xlarge/customize_paged_view_wallpaper.xml b/res/layout-xlarge/customize_paged_view_wallpaper.xml
new file mode 100644
index 0000000..e3be86d
--- /dev/null
+++ b/res/layout-xlarge/customize_paged_view_wallpaper.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+<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="wrap_content"
+ android:layout_height="365dp"
+ android:paddingLeft="12.5dp"
+ android:paddingRight="12.5dp"
+ android:paddingBottom="50dp"
+ android:gravity="top"
+ android:orientation="vertical"
+
+ launcher:blurColor="#FF6B8CF0"
+ launcher:outlineColor="#FF8CD2FF">
+
+ <!-- The preview image for the wallpaper. -->
+ <ImageView
+ android:id="@+id/wallpaper_preview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"
+ android:scaleType="fitStart" />
+
+ <!-- The divider image. -->
+ <ImageView
+ android:id="@+id/divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ 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/wallpaper_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="left"
+
+ 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-xlarge/customize_paged_view_widget.xml b/res/layout-xlarge/customize_paged_view_widget.xml
new file mode 100644
index 0000000..3b95ebc
--- /dev/null
+++ b/res/layout-xlarge/customize_paged_view_widget.xml
@@ -0,0 +1,80 @@
+<?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.
+-->
+<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="wrap_content"
+ android:layout_height="365dp"
+ android:paddingLeft="12.5dp"
+ android:paddingTop="12.5dp"
+ android:paddingRight="12.5dp"
+ android:paddingBottom="50dp"
+ android:gravity="top"
+ android:orientation="vertical"
+
+ launcher:blurColor="#FF6B8CF0"
+ launcher:outlineColor="#FF8CD2FF">
+
+ <!-- The icon of the widget. -->
+ <ImageView
+ android:id="@+id/widget_preview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"
+ android:scaleType="fitStart" />
+
+ <!-- The divider image. -->
+ <ImageView
+ android:id="@+id/divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="10dp"
+ android:paddingBottom="10dp"
+ android:src="@drawable/widget_divider" />
+
+ <!-- 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:gravity="left"
+
+ 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:gravity="left"
+
+ 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-xlarge/external_widget_drop_list_item.xml b/res/layout-xlarge/external_widget_drop_list_item.xml
new file mode 100644
index 0000000..84f40ed
--- /dev/null
+++ b/res/layout-xlarge/external_widget_drop_list_item.xml
@@ -0,0 +1,39 @@
+<?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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+
+ android:layout_width="match_parent"
+ android:layout_height="64dp">
+ <ImageView
+ android:id="@+id/provider_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginLeft="20dp"
+ android:maxWidth="32dp"
+ android:maxHeight="32dp"
+ android:scaleType="fitCenter"
+ android:src="@drawable/ic_launcher_application" />
+ <TextView
+ android:id="@+id/provider"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="5dp"
+ android:gravity="center_vertical"
+ android:textSize="18sp" />
+</LinearLayout>
diff --git a/res/layout-xlarge/tab_widget_indicator.xml b/res/layout-xlarge/tab_widget_indicator.xml
new file mode 100644
index 0000000..1b3f1c0
--- /dev/null
+++ b/res/layout-xlarge/tab_widget_indicator.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:paddingLeft="40dp"
+ android:paddingRight="40dp"
+ android:paddingTop="15dp"
+ android:paddingBottom="20dp"
+
+ android:textColor="@color/tab_widget_indicator_color"
+ android:background="@drawable/tab_widget_indicator_selector"
+ android:textSize="20sp"
+ android:shadowColor="#393939"
+ android:shadowDx="0.0"
+ android:shadowDy="1.0"
+ android:shadowRadius="1.0" />
diff --git a/res/layout-xlarge/wallpaper_chooser.xml b/res/layout-xlarge/wallpaper_chooser.xml
new file mode 100644
index 0000000..b48dbd9
--- /dev/null
+++ b/res/layout-xlarge/wallpaper_chooser.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wallpaper_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="24dp"
+ android:gravity="center">
+ <GridView
+ android:id="@+id/gallery"
+ android:layout_width="636dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:numColumns="3"
+ android:stretchMode="none"
+ android:columnWidth="@dimen/live_wallpaper_column_width"
+ android:verticalSpacing="0dp"
+ android:horizontalSpacing="0dp"
+ android:drawSelectorOnTop="false" />
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+
+ android:gravity="center"
+ android:visibility="gone"
+
+ android:text="@string/wallpaper_chooser_empty"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout-xlarge/wallpaper_chooser_base.xml b/res/layout-xlarge/wallpaper_chooser_base.xml
new file mode 100644
index 0000000..ba5ac53
--- /dev/null
+++ b/res/layout-xlarge/wallpaper_chooser_base.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
diff --git a/res/layout-xlarge/wallpaper_item.xml b/res/layout-xlarge/wallpaper_item.xml
new file mode 100644
index 0000000..9a596cb
--- /dev/null
+++ b/res/layout-xlarge/wallpaper_item.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/live_wallpaper_grid_item_padding">
+ <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wallpaper_image"
+ android:layout_width="@dimen/wallpaper_chooser_grid_width"
+ android:layout_height="@dimen/wallpaper_chooser_grid_height"
+ android:scaleType="centerCrop"
+ android:adjustViewBounds="false"
+ android:focusable="false"
+ android:padding="0dp" />
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/home_customization_drawer_item.xml b/res/layout/home_customization_drawer_item.xml
new file mode 100644
index 0000000..4d61dbf
--- /dev/null
+++ b/res/layout/home_customization_drawer_item.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="200dip"
+ android:layout_height="200dip"
+ android:padding="20dip"
+ android:orientation="vertical"
+ android:gravity="center_horizontal|center_vertical|clip_vertical"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="#ffffffff" />
\ No newline at end of file
diff --git a/res/layout/home_customization_drawer_widget.xml b/res/layout/home_customization_drawer_widget.xml
new file mode 100644
index 0000000..1581308
--- /dev/null
+++ b/res/layout/home_customization_drawer_widget.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="600dip"
+ android:layout_height="match_parent"
+ android:padding="20dip"
+ android:orientation="vertical"
+ android:gravity="center_horizontal|center_vertical|clip_vertical"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="#ffffffff" />
\ No newline at end of file
diff --git a/res/layout/wallpaper_chooser_base.xml b/res/layout/wallpaper_chooser_base.xml
new file mode 100644
index 0000000..fa8ea93
--- /dev/null
+++ b/res/layout/wallpaper_chooser_base.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <fragment class="com.android.launcher2.WallpaperChooserDialogFragment"
+ android:id="@+id/wallpaper_chooser_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</FrameLayout>
diff --git a/res/layout/wallpaper_item.xml b/res/layout/wallpaper_item.xml
index 6727483..cfd79e2 100644
--- a/res/layout/wallpaper_item.xml
+++ b/res/layout/wallpaper_item.xml
@@ -15,6 +15,7 @@
-->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/wallpaper_image"
android:background="?android:attr/galleryItemBackground"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/raw/allapps.rs b/res/raw/allapps.rs
deleted file mode 100644
index af5abd3..0000000
--- a/res/raw/allapps.rs
+++ /dev/null
@@ -1,427 +0,0 @@
-#pragma version(1)
-#pragma stateVertex(PV)
-#pragma stateFragment(PFTexNearest)
-#pragma stateStore(PSIcons)
-
-#define PI 3.14159f
-
-int g_SpecialHWWar;
-
-// Attraction to center values from page edge to page center.
-float g_AttractionTable[9];
-float g_FrictionTable[9];
-float g_PhysicsTableSize;
-
-float g_PosPage;
-float g_PosVelocity;
-float g_LastPositionX;
-int g_LastTouchDown;
-float g_DT;
-int g_LastTime;
-int g_PosMax;
-float g_Zoom;
-float g_Animation;
-float g_OldPosPage;
-float g_OldPosVelocity;
-float g_OldZoom;
-float g_MoveToTotalTime;
-float g_MoveToTime;
-float g_MoveToOldPos;
-
-int g_Cols;
-int g_Rows;
-
-// Drawing constants, should be parameters ======
-#define VIEW_ANGLE 1.28700222f
-
-int g_DrawLastFrame;
-int lastFrame(int draw) {
- // We draw one extra frame to work around the last frame post bug.
- // We also need to track if we drew the last frame to deal with large DT
- // in the physics.
- int ret = g_DrawLastFrame | draw;
- g_DrawLastFrame = draw;
- return ret; // should return draw instead.
-}
-
-void updateReadback() {
- if ((g_OldPosPage != g_PosPage) ||
- (g_OldPosVelocity != g_PosVelocity) ||
- (g_OldZoom != g_Zoom)) {
-
- g_OldPosPage = g_PosPage;
- g_OldPosVelocity = g_PosVelocity;
- g_OldZoom = g_Zoom;
-
- int i[3];
- i[0] = g_PosPage * (1 << 16);
- i[1] = g_PosVelocity * (1 << 16);
- i[2] = g_OldZoom * (1 << 16);
- sendToClient(&i[0], 1, 12, 1);
- }
-}
-
-void setColor(float r, float g, float b, float a) {
- if (g_SpecialHWWar) {
- color(0, 0, 0, 0.001f);
- } else {
- color(r, g, b, a);
- }
-}
-
-void init() {
- g_AttractionTable[0] = 20.0f;
- g_AttractionTable[1] = 20.0f;
- g_AttractionTable[2] = 20.0f;
- g_AttractionTable[3] = 10.0f;
- g_AttractionTable[4] = -10.0f;
- g_AttractionTable[5] = -20.0f;
- g_AttractionTable[6] = -20.0f;
- g_AttractionTable[7] = -20.0f;
- g_AttractionTable[8] = -20.0f; // dup 7 to avoid a clamp later
- g_FrictionTable[0] = 10.0f;
- g_FrictionTable[1] = 10.0f;
- g_FrictionTable[2] = 11.0f;
- g_FrictionTable[3] = 15.0f;
- g_FrictionTable[4] = 15.0f;
- g_FrictionTable[5] = 11.0f;
- g_FrictionTable[6] = 10.0f;
- g_FrictionTable[7] = 10.0f;
- g_FrictionTable[8] = 10.0f; // dup 7 to avoid a clamp later
- g_PhysicsTableSize = 7;
-
- g_PosVelocity = 0;
- g_PosPage = 0;
- g_LastTouchDown = 0;
- g_LastPositionX = 0;
- g_Zoom = 0;
- g_Animation = 1.f;
- g_SpecialHWWar = 1;
- g_MoveToTime = 0;
- g_MoveToOldPos = 0;
- g_MoveToTotalTime = 0.2f; // Duration of scrolling 1 line
-}
-
-void resetHWWar() {
- g_SpecialHWWar = 1;
-}
-
-void move() {
- if (g_LastTouchDown) {
- float dx = -(state->newPositionX - g_LastPositionX);
- g_PosVelocity = 0;
- g_PosPage += dx * 5.2f;
-
- float pmin = -0.49f;
- float pmax = g_PosMax + 0.49f;
- g_PosPage = clampf(g_PosPage, pmin, pmax);
- }
- g_LastTouchDown = state->newTouchDown;
- g_LastPositionX = state->newPositionX;
- g_MoveToTime = 0;
- //debugF("Move P", g_PosPage);
-}
-
-void moveTo() {
- g_MoveToTime = g_MoveToTotalTime;
- g_PosVelocity = 0;
- g_MoveToOldPos = g_PosPage;
-
- // debugF("======= moveTo", state->targetPos);
-}
-
-void setZoom() {
- g_Zoom = state->zoomTarget;
- g_DrawLastFrame = 1;
- updateReadback();
-}
-
-void fling() {
- g_LastTouchDown = 0;
- g_PosVelocity = -state->flingVelocity * 4;
- float av = fabsf(g_PosVelocity);
- float minVel = 3.5f;
-
- minVel *= 1.f - (fabsf(fracf(g_PosPage + 0.5f) - 0.5f) * 0.45f);
-
- if (av < minVel && av > 0.2f) {
- if (g_PosVelocity > 0) {
- g_PosVelocity = minVel;
- } else {
- g_PosVelocity = -minVel;
- }
- }
-
- if (g_PosPage <= 0) {
- g_PosVelocity = maxf(0, g_PosVelocity);
- }
- if (g_PosPage > g_PosMax) {
- g_PosVelocity = minf(0, g_PosVelocity);
- }
-}
-
-float
-modf(float x, float y)
-{
- return x-(y*floorf(x/y));
-}
-
-
-/*
- * Interpolates values in the range 0..1 to a curve that eases in
- * and out.
- */
-float
-getInterpolation(float input) {
- return (cosf((input + 1) * PI) / 2.0f) + 0.5f;
-}
-
-
-void updatePos() {
- if (g_LastTouchDown) {
- return;
- }
-
- float tablePosNorm = fracf(g_PosPage + 0.5f);
- float tablePosF = tablePosNorm * g_PhysicsTableSize;
- int tablePosI = tablePosF;
- float tablePosFrac = tablePosF - tablePosI;
- float accel = lerpf(g_AttractionTable[tablePosI],
- g_AttractionTable[tablePosI + 1],
- tablePosFrac) * g_DT;
- float friction = lerpf(g_FrictionTable[tablePosI],
- g_FrictionTable[tablePosI + 1],
- tablePosFrac) * g_DT;
-
- if (g_MoveToTime) {
- // New position is old posiition + (total distance) * (interpolated time)
- g_PosPage = g_MoveToOldPos + (state->targetPos - g_MoveToOldPos) * getInterpolation((g_MoveToTotalTime - g_MoveToTime) / g_MoveToTotalTime);
- g_MoveToTime -= g_DT;
- if (g_MoveToTime <= 0) {
- g_MoveToTime = 0;
- g_PosPage = state->targetPos;
- }
- return;
- }
-
- // If our velocity is low OR acceleration is opposing it, apply it.
- if (fabsf(g_PosVelocity) < 4.0f || (g_PosVelocity * accel) < 0) {
- g_PosVelocity += accel;
- }
- //debugF("g_PosPage", g_PosPage);
- //debugF(" g_PosVelocity", g_PosVelocity);
- //debugF(" friction", friction);
- //debugF(" accel", accel);
-
- // Normal physics
- if (g_PosVelocity > 0) {
- g_PosVelocity -= friction;
- g_PosVelocity = maxf(g_PosVelocity, 0);
- } else {
- g_PosVelocity += friction;
- g_PosVelocity = minf(g_PosVelocity, 0);
- }
-
- if ((friction > fabsf(g_PosVelocity)) && (friction > fabsf(accel))) {
- // Special get back to center and overcome friction physics.
- float t = tablePosNorm - 0.5f;
- if (fabsf(t) < (friction * g_DT)) {
- // really close, just snap
- g_PosPage = roundf(g_PosPage);
- g_PosVelocity = 0;
- } else {
- if (t > 0) {
- g_PosVelocity = -friction;
- } else {
- g_PosVelocity = friction;
- }
- }
- }
-
- // Check for out of boundry conditions.
- if (g_PosPage < 0 && g_PosVelocity < 0) {
- float damp = 1.0 + (g_PosPage * 4);
- damp = clampf(damp, 0.f, 0.9f);
- g_PosVelocity *= damp;
- }
- if (g_PosPage > g_PosMax && g_PosVelocity > 0) {
- float damp = 1.0 - ((g_PosPage - g_PosMax) * 4);
- damp = clampf(damp, 0.f, 0.9f);
- g_PosVelocity *= damp;
- }
-
- g_PosPage += g_PosVelocity * g_DT;
- g_PosPage = clampf(g_PosPage, -0.49, g_PosMax + 0.49);
-}
-
-
-void
-draw_home_button()
-{
- setColor(1.0f, 1.0f, 1.0f, 1.0f);
- bindTexture(NAMED_PFTexNearest, 0, state->homeButtonId);
-
- float w = getWidth();
- float h = getHeight();
-
- float x;
- float y;
- if (getWidth() > getHeight()) {
- x = w - (params->homeButtonTextureWidth * (1 - g_Animation)) + 20;
- y = (h - params->homeButtonTextureHeight) * 0.5f;
- } else {
- x = (w - params->homeButtonTextureWidth) / 2;
- y = -g_Animation * params->homeButtonTextureHeight;
- y -= 30; // move the house to the edge of the screen as it doesn't fill the texture.
- }
-
- drawSpriteScreenspace(x, y, 0, params->homeButtonTextureWidth, params->homeButtonTextureHeight);
-}
-
-void drawFrontGrid(float rowOffset, float p)
-{
- float h = getHeight();
- float w = getWidth();
-
- int intRowOffset = rowOffset;
- float rowFrac = rowOffset - intRowOffset;
- float colWidth = 120.f;//getWidth() / 4;
- float rowHeight = colWidth + 25.f;
- float yoff = 0.5f * h + 1.5f * rowHeight;
-
- int row, col;
- int colCount = 4;
- if (w > h) {
- colCount = 6;
- rowHeight -= 12.f;
- yoff = 0.47f * h + 1.0f * rowHeight;
- }
-
- int iconNum = (intRowOffset - 5) * colCount;
-
-
- bindProgramVertex(NAMED_PVCurve);
-
- vpConstants->Position.z = p;
-
- setColor(1.0f, 1.0f, 1.0f, 1.0f);
- for (row = -5; row < 15; row++) {
- float y = yoff - ((-rowFrac + row) * rowHeight);
-
- for (col=0; col < colCount; col++) {
- if (iconNum >= state->iconCount) {
- return;
- }
-
- if (iconNum >= 0) {
- float x = colWidth * col + (colWidth / 2);
- vpConstants->Position.x = x + 0.2f;
-
- if (state->selectedIconIndex == iconNum && !p) {
- bindProgramFragment(NAMED_PFTexNearest);
- bindTexture(NAMED_PFTexNearest, 0, state->selectedIconTexture);
- vpConstants->ImgSize.x = SELECTION_TEXTURE_WIDTH_PX;
- vpConstants->ImgSize.y = SELECTION_TEXTURE_HEIGHT_PX;
- vpConstants->Position.y = y - (SELECTION_TEXTURE_HEIGHT_PX - ICON_TEXTURE_HEIGHT_PX) * 0.5f;
- drawSimpleMesh(NAMED_SMCell);
- }
-
- bindProgramFragment(NAMED_PFTexMip);
- vpConstants->ImgSize.x = ICON_TEXTURE_WIDTH_PX;
- vpConstants->ImgSize.y = ICON_TEXTURE_HEIGHT_PX;
- vpConstants->Position.y = y - 0.2f;
- bindTexture(NAMED_PFTexMip, 0, loadI32(ALLOC_ICON_IDS, iconNum));
- drawSimpleMesh(NAMED_SMCell);
-
- bindProgramFragment(NAMED_PFTexMipAlpha);
- vpConstants->ImgSize.x = 120.f;
- vpConstants->ImgSize.y = 64.f;
- vpConstants->Position.y = y - 64.f - 0.2f;
- bindTexture(NAMED_PFTexMipAlpha, 0, loadI32(ALLOC_LABEL_IDS, iconNum));
- drawSimpleMesh(NAMED_SMCell);
- }
- iconNum++;
- }
- }
-}
-
-
-int
-main(int launchID)
-{
- // Compute dt in seconds.
- int newTime = uptimeMillis();
- g_DT = (newTime - g_LastTime) / 1000.f;
- g_LastTime = newTime;
-
- if (!g_DrawLastFrame) {
- // If we stopped rendering we cannot use DT.
- // assume 30fps in this case.
- g_DT = 0.033f;
- }
- // physics may break if DT is large.
- g_DT = minf(g_DT, 0.2f);
-
- if (g_Zoom != state->zoomTarget) {
- float dz = g_DT * 1.7f;
- if (state->zoomTarget < 0.5f) {
- dz = -dz;
- }
- if (fabsf(g_Zoom - state->zoomTarget) < fabsf(dz)) {
- g_Zoom = state->zoomTarget;
- } else {
- g_Zoom += dz;
- }
- updateReadback();
- }
- g_Animation = powf(1-g_Zoom, 3);
-
- // Set clear value to dim the background based on the zoom position.
- if ((g_Zoom < 0.001f) && (state->zoomTarget < 0.001f) && !g_SpecialHWWar) {
- pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- // When we're zoomed out and not tracking motion events, reset the pos to 0.
- if (!g_LastTouchDown) {
- g_PosPage = 0;
- }
- return lastFrame(0);
- } else {
- pfClearColor(0.0f, 0.0f, 0.0f, g_Zoom);
- }
-
- // icons & labels
- int iconCount = state->iconCount;
- if (getWidth() > getHeight()) {
- g_Cols = 6;
- g_Rows = 3;
- } else {
- g_Cols = 4;
- g_Rows = 4;
- }
- g_PosMax = ((iconCount + (g_Cols-1)) / g_Cols) - g_Rows;
- if (g_PosMax < 0) g_PosMax = 0;
-
- updatePos();
- updateReadback();
-
- //debugF(" draw g_PosPage", g_PosPage);
-
- // Draw the icons ========================================
- drawFrontGrid(g_PosPage, g_Animation);
-
- bindProgramFragment(NAMED_PFTexNearest);
- draw_home_button();
-
- // This is a WAR to do a rendering pass without drawing during init to
- // force the driver to preload and compile its shaders.
- // Without this the first animation does not appear due to the time it
- // takes to init the driver state.
- if (g_SpecialHWWar) {
- g_SpecialHWWar = 0;
- return 1;
- }
-
- // Bug workaround where the last frame is not always displayed
- // So we keep rendering until the bug is fixed.
- return lastFrame((g_PosVelocity != 0) || fracf(g_PosPage) || g_Zoom != state->zoomTarget || (g_MoveToTime != 0));
-}
-
diff --git a/res/values-ar-xlarge/strings.xml b/res/values-ar-xlarge/strings.xml
new file mode 100644
index 0000000..2182311
--- /dev/null
+++ b/res/values-ar-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"تحديد خلفية"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"لا تتوفر أية خلفيات"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"إلغاء"</string>
+</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 48792e4..05b10e7 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"اختيار خلفية من"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"تعيين خلفية"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"الخلفيات"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"لم يتم تثبيت التطبيق على هاتفك."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"لم يتم تثبيت التطبيق."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"تهيئة..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"الأدوات"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"المجلدات"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"المزيد"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"الخلفيات"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"اختصارات التطبيقات"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"ستكون هذه علامة تبويب الخلفيات"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"الكل"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"التطبيقات"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"الألعاب"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"منزّلة"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"لم يتم العثور على ألعاب"</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"لم يُعثر على تطبيقات منزّلة"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"تعذر إسقاط العنصر على هذه الشاشة الرئيسية"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"تحديد أداة للإنشاء"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"اسم المجلد"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"إعادة تسمية المجلد"</string>
<string name="rename_action" msgid="6016003384693240896">"موافق"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"تحديد اختصار"</string>
<string name="title_select_application" msgid="8031072293115454221">"تحديد تطبيق"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"تحديد مجلد"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"جميع التطبيقات"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"التطبيقات"</string>
<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="menu_add" msgid="3065046628354640854">"إضافة"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"إدارة التطبيقات"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"خلفية"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"التنبيهات"</string>
<string name="menu_gestures" msgid="514678675575912237">"الإيماءات"</string>
<string name="menu_settings" msgid="6233960148378443661">"الإعدادات"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"إزالة التطبيق"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"تفاصيل التطبيق"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"تم تحديد تطبيق واحد"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"تم تحديد أداة واحدة"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"تم تحديد مجلد واحد"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"تم تحديد اختصارٍ واحد"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"اختصارات التثبيت"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"للسماح للتطبيقات بإضافة الاختصارات بدون تدخل المستخدم."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"إزالة الاختصارات"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"كتابة إعدادات الشاشة الرئيسية والاختصارات"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"للسماح لتطبيق ما بتغيير الإعدادات والاختصارات في الشاشة الرئيسية."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"حدثت مشكلة أثناء تحميل الأداة"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"هذا تطبيق نظام وتتعذر إزالته."</string>
</resources>
diff --git a/res/values-bg-xlarge/strings.xml b/res/values-bg-xlarge/strings.xml
new file mode 100644
index 0000000..5ca1b46
--- /dev/null
+++ b/res/values-bg-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Избор на тапет"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Няма налични тапети"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Отказ"</string>
+</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index c052150..b6412fa 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Избор на тапет от"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Задаване на тапет"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Тапети"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Приложението не е инсталирано на телефона ви."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Приложението не е инсталирано."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Конфигуриране..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Приспособления"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Папки"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Още"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Тапети"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Преки пътища на приложения"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Това ще бъде разделът с тапети"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Всички"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Приложения"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Игри"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Изтеглени"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Няма намерени игри."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Няма изтеглени приложения"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Елементът не можа да се премести на началния екран"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Избор на създаващо приспособление"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Име на папка"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Преименуване на папка"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Избор на пряк път"</string>
<string name="title_select_application" msgid="8031072293115454221">"Избиране на приложение"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Избор на папка"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Всички приложения"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Приложения"</string>
<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="menu_add" msgid="3065046628354640854">"Добавяне"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Управление на приложенията"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Тапет"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Известия"</string>
<string name="menu_gestures" msgid="514678675575912237">"Жестове"</string>
<string name="menu_settings" msgid="6233960148378443661">"Настройки"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Деинсталиране на приложението"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Подробности за приложението"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Избрано е 1 приложение"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Избрано е 1 приспособление"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Избрана е 1 папка"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Избран е 1 пряк път"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"инсталиране на преки пътища"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Разрешава на приложение да добави преки пътища без намеса на потребителя."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"деинсталиране на преките пътища"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"въведете настройките за „Начало“ и преки пътища"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Разрешава на приложение да промени настройките и преките пътища в „Начало“."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Проблем при зареждане на приспособление"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Това е системно приложение и не може да се деинсталира."</string>
</resources>
diff --git a/res/values-ca-xlarge/strings.xml b/res/values-ca-xlarge/strings.xml
new file mode 100644
index 0000000..63f4a09
--- /dev/null
+++ b/res/values-ca-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Seleccionar un fons de pantalla"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"No hi ha empaperats disponibles"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Cancel·la"</string>
+</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 796f1d2..e8c92e3 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Selecció d\'un empaperat de"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Defineix l\'empaperat"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Empaperats"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"L\'aplicació no està instal·lada al telèfon."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"L\'aplicació no està instal·lada."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configura..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Carpetes"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Més"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Empaperats"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Dreceres d\'aplicacions"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Aquesta serà la pestanya dels empaperats"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Totes"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplicacions"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Jocs"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Baixat"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"No s\'ha trobat cap joc."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"No hi ha aplic. baixades."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"No s\'ha pogut trasll. l\'element a la pant. d\'inici"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Selecciona un widget per crear-lo"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nom de la carpeta"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Canvi de nom de carpeta"</string>
<string name="rename_action" msgid="6016003384693240896">"D\'acord"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Selecció d\'una drecera"</string>
<string name="title_select_application" msgid="8031072293115454221">"Selecciona l\'aplicació"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Selecció d\'una carpeta"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Totes les aplicacions"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplicacions"</string>
<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="menu_add" msgid="3065046628354640854">"Afegeix"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gestiona les aplicacions"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Empaperat"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notificacions"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestos"</string>
<string name="menu_settings" msgid="6233960148378443661">"Configuració"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Desinstal·la l\'aplicació"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Detalls de l\'aplicació"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 aplicació seleccionada"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget seleccionat"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 carpeta seleccionada"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 drecera seleccionada"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"instal·lar dreceres"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Permet a una aplicació afegir dreceres sense intervenció de l\'usuari."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"desinstal·lar dreceres"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"escriure la configuració i les dreceres de la pantalla Inici"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Permet que una aplicació canviï la configuració i les dreceres de la pantalla Inici."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"S\'ha produït un problema en carregar el widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Això és una aplicació del sistema i no es pot desinstal·lar."</string>
</resources>
diff --git a/res/values-cs-xlarge/strings.xml b/res/values-cs-xlarge/strings.xml
new file mode 100644
index 0000000..d3e5aa8
--- /dev/null
+++ b/res/values-cs-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Výběr tapety"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"K dispozici nejsou žádné tapety"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Zrušit"</string>
+</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 0f28387..f134a7c 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Vybrat tapetu ze složky"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Nastavit tapetu"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Tapety"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Aplikace není v telefonu nainstalována."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Aplikace není nainstalována"</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurace..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgety"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Složky"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Další"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Tapety"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Zástupci aplikací"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Toto bude karta Tapety"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Vše"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplikace"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Hry"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Stažené"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nenalezeny žádné hry."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Žádné stažené aplikace."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Na tuto plochu nelze položku přetáhnout"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Vyberte widget"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Název složky"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Přejmenovat složku"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Vyberte zástupce"</string>
<string name="title_select_application" msgid="8031072293115454221">"Výběr aplikace"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Vybrat složku"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Všechny aplikace"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplikace"</string>
<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="menu_add" msgid="3065046628354640854">"Přidat"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Spravovat aplikace"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Tapeta"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Oznámení"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gesta"</string>
<string name="menu_settings" msgid="6233960148378443661">"Nastavení"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Odinstalovat aplikaci"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Podrobnosti o aplikaci"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Vybrána 1 aplikace"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Vybrán 1 widget"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Vybrána 1 složka"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Vybrán 1 zástupce"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"instalovat zástupce"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Povoluje aplikaci přidat zástupce bez zásahu uživatele."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"odinstalovat zástupce"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"zápis nastavení a odkazů plochy"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Povoluje aplikaci změnit nastavení a odkazy plochy."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problém s načtením widgetu"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Toto je systémová aplikace a nelze ji odinstalovat."</string>
</resources>
diff --git a/res/values-da-xlarge/strings.xml b/res/values-da-xlarge/strings.xml
new file mode 100644
index 0000000..76ee7b0
--- /dev/null
+++ b/res/values-da-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Vælg tapet"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Ingen tilgængelige tapeter"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Annuller"</string>
+</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index d23e046..a9362e0 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Vælg tapet fra"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Angiv tapet"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Tapeter"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Programmet er ikke installeret på din telefon."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Applikationen er ikke installeret."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurer ..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mapper"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Flere"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Tapeter"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Programgenvej"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Dette er fanen for tapeter"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Alle"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Programmer"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Spil"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Downloadet"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Ingen spil."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Ingen hentede programmer."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Kunne ikke slippe elementet på denne startskærm"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Vælg widget for at oprette"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Mappenavn"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Omdøb mappe"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Vælg genvej"</string>
<string name="title_select_application" msgid="8031072293115454221">"Vælg program"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Vælg mappe"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Alle programmer"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Programmer"</string>
<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="menu_add" msgid="3065046628354640854">"Tilføj"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Administrer programmer"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Tapet"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Meddelelser"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestus"</string>
<string name="menu_settings" msgid="6233960148378443661">"Indstillinger"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Afinstaller program"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Programoplysninger"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 program er valgt"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget er valgt"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 mappe er valgt"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 genvej er valgt"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"installer genveje"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Tillader, at et program tilføjer genveje uden brugerindgriben."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"afinstaller genveje"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"skriv indstillinger og genveje for Start"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Tillader, at et program ændrer indstillingerne og genvejene i Start."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Der er problemer med indlæsning af widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Dette er et systemprogram, som ikke kan afinstalleres."</string>
</resources>
diff --git a/res/values-de-xlarge/strings.xml b/res/values-de-xlarge/strings.xml
new file mode 100644
index 0000000..148a9af
--- /dev/null
+++ b/res/values-de-xlarge/strings.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Hintergrund auswählen"</string>
+ <!-- no translation found for wallpaper_chooser_empty (7358237455389125747) -->
+ <skip />
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Abbrechen"</string>
+</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 5a4186b..7964dba 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Hintergrund auswählen"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Hintergrund festlegen"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Hintergrundbilder"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Anwendung ist nicht auf dem Telefon installiert."</string>
+ <!-- outdated translation 3571057450431950427 --> <string name="activity_not_found" msgid="5591731020063337696">"Anwendung ist nicht auf dem Telefon installiert."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurieren..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Ordner"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Mehr"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Hintergründe"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"App-Verknüpfungen"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Dies ist der Tab \"Hintergründe\""</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Alle"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Apps"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Spiele"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Heruntergeladen"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Keine Spiele gefunden."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Keine heruntergeladenen Apps"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Element wurde nicht auf Startbildschirm abgelegt."</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Widget für Erstellung auswählen"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Ordnername"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Ordner umbenennen"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Tastenkürzel auswählen"</string>
<string name="title_select_application" msgid="8031072293115454221">"Anwendung auswählen"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Ordner auswählen"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Alle Anwendungen"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Anwendungen"</string>
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Startseite"</string>
+ <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Entfernen"</string>
+ <!-- outdated translation 2536335964588694907 --> <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Löschen"</string>
<string name="menu_add" msgid="3065046628354640854">"Hinzufügen"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Apps verwalten"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Hintergrund"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Benachrichtigungen"</string>
<string name="menu_gestures" msgid="514678675575912237">"Bewegungen"</string>
<string name="menu_settings" msgid="6233960148378443661">"Einstellungen"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Anwendung deinstallieren"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Anwendungsdetails"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 Anwendung ausgewählt"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 Widget ausgewählt"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 Ordner ausgewählt"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 Verknüpfung ausgewählt"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"Verknüpfungen installieren"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Ermöglicht einer Anwendung das Hinzufügen von Verknüpfungen ohne Eingriff des Nutzers."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"Verknüpfungen deinstallieren"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"Einstellungen und Shortcuts für Startseite schreiben"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Ermöglicht einer Anwendung, die Einstellungen und Shortcuts auf der Startseite zu ändern."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problem beim Laden des Widgets"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Dies ist eine Systemanwendung, die nicht deinstalliert werden kann."</string>
</resources>
diff --git a/res/values-el-xlarge/strings.xml b/res/values-el-xlarge/strings.xml
new file mode 100644
index 0000000..66cbfde
--- /dev/null
+++ b/res/values-el-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Επιλογή ταπετσαρίας"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Δεν υπάρχουν διαθέσιμες ταπετσαρίες"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Ακύρωση"</string>
+</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 1e27440..4bc4b49 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Επιλογή ταπετσαρίας από"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Ορισμός ταπετσαρίας"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Ταπετσαρίες"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Η εφαρμογή δεν έχει εγκατασταθεί στο τηλέφωνό σας."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Η εφαρμογή δεν έχει εγκατασταθεί."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Διαμόρφωση..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Γραφικά στοιχεία"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Φάκελοι"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Περισσότερα"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Ταπετσαρίες"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Συντομεύσεις Εφαρμογών"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Αυτή θα είναι η καρτέλα ταπετσαριών"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Κάθε ηλικία"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Εφαρμογές"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Παιχνίδια"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Η λήψη ολοκληρώθηκε"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Δεν βρέθηκαν παιχνίδια."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Δεν βρέθηκαν ληφθ. εφαρμ."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Δεν έγινε η απόθ. του στοιχείου στην αρχική οθόνη"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Επιλογή γραφ. στοιχείου δημιουργίας"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Όνομα φακέλου"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Μετονομασία φακέλου"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Επιλογή συντόμευσης"</string>
<string name="title_select_application" msgid="8031072293115454221">"Επιλέξτε εφαρμογή"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Επιλογή φακέλου"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Όλες οι εφαρμογές"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Εφαρμογές"</string>
<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="menu_add" msgid="3065046628354640854">"Προσθήκη"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Διαχείριση εφαρμογών"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Ταπετσαρία"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Ειδοποιήσεις"</string>
<string name="menu_gestures" msgid="514678675575912237">"Χειρονομίες"</string>
<string name="menu_settings" msgid="6233960148378443661">"Ρυθμίσεις"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Κατάργηση εγκατάστασης εφαρμογής"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Λεπτομέρειες εφαρμογής"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Επιλέχθηκε 1 εφαρμογή"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Επιλέχθηκε 1 γραφικό στοιχείο"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Επιλέχθηκε 1 φάκελος"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Επιλέχθηκε 1 συντόμευση"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"εγκατάσταση συντομεύσεων"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων χωρίς την παρέμβαση του χρήστη."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"κατάργηση εγκατάστασης συντομεύσεων"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"εγγραφή ρυθμίσεων και συντομεύσεων αρχικής οθόνης"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Επιτρέπει σε μια εφαρμογή την αλλαγή των ρυθμίσεων και των συντομεύσεων στην αρχική οθόνη."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Παρουσιάστηκε πρόβλημα στη φόρτωση του γραφικού στοιχείου"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Αυτή είναι εφαρμογή του συστήματος και δεν είναι δυνατή η κατάργηση της εγκατάστασής της."</string>
</resources>
diff --git a/res/values-en-rGB-xlarge/strings.xml b/res/values-en-rGB-xlarge/strings.xml
new file mode 100644
index 0000000..60042b2
--- /dev/null
+++ b/res/values-en-rGB-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Select wallpaper"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"No wallpaper available"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Cancel"</string>
+</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index c332ffe..2e0f2fe 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Select wallpaper from"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Set wallpaper"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Wallpaper"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Application is not installed on your phone."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Application is not installed."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configure..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Folders"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"More"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Wallpaper"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"App Shortcuts"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"This will be the wallpaper tab"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"All"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Apps"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Games"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Downloaded"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"No games found."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"No downloaded apps found."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Could not drop item onto this home screen"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Select widget to create"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Folder name"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Rename folder"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Select shortcut"</string>
<string name="title_select_application" msgid="8031072293115454221">"Select application"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Select folder"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"All applications"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Apps"</string>
<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="menu_add" msgid="3065046628354640854">"Add"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Manage apps"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Wallpaper"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notifications"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestures"</string>
<string name="menu_settings" msgid="6233960148378443661">"Settings"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Uninstall application"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Application details"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 application selected"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget selected"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 folder selected"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 shortcut selected"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"install shortcuts"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Allows an application to add shortcuts without user intervention."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"uninstall shortcuts"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"write Home settings and shortcuts"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Allows an application to change the settings and shortcuts in Home."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problem loading widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"This is a system application and cannot be uninstalled."</string>
</resources>
diff --git a/res/values-es-rUS-xlarge/strings.xml b/res/values-es-rUS-xlarge/strings.xml
new file mode 100644
index 0000000..349e3eb
--- /dev/null
+++ b/res/values-es-rUS-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Seleccionar fondo de pantalla"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"No hay fondos de pantalla disponibles"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Cancelar"</string>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 6b46ab3..1d853dd 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Seleccionar papel tapiz desde"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Definir como fondo de pantalla"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Papeles tapiz"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"La aplicación no está instalada en tu computadora."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"La aplicación no está instalada."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configurar..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Carpetas"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Más"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Papeles tapiz"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Accesos directos a aplicaciones"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Ésta será la pestaña para los papeles tapiz"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Todos"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplicaciones"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Juegos"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Descargado"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"No se encontraron juegos."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"No se encontraron descargas de aplicaciones."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"No se pudo colocar el elemento en esta pantalla principal"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Seleccionar widget para crear"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nombre de carpeta"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Cambiar nombre de carpeta"</string>
<string name="rename_action" msgid="6016003384693240896">"Aceptar"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Seleccionar acceso directo"</string>
<string name="title_select_application" msgid="8031072293115454221">"Seleccionar aplicación"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Seleccionar carpeta"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Todas las aplicaciones"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplicaciones"</string>
<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="menu_add" msgid="3065046628354640854">"Agregar"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Administrar aplicaciones"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Papel tapiz"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notificaciones"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestos"</string>
<string name="menu_settings" msgid="6233960148378443661">"Configuración"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Desinstalar la aplicación"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Detalles de la aplicación"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Se seleccionó 1 aplicación"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Se seleccionó 1 widget"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Se seleccionó 1 carpeta"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Se seleccionó 1 acceso directo"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"instalar accesos directos"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Permite a una aplicación agregar accesos directos sin intervención del usuario."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"desinstalar papel tapiz"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"escribir configuración y accesos directos de la página principal"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Permite a una aplicación cambiar la configuración y los accesos directos de la página principal."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problema al cargar el widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Esta es una aplicación de sistema y no puede desinstalarse."</string>
</resources>
diff --git a/res/values-es-xlarge/strings.xml b/res/values-es-xlarge/strings.xml
new file mode 100644
index 0000000..f43f72a
--- /dev/null
+++ b/res/values-es-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Seleccionar fondo de pantalla"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"No hay fondos de pantalla disponibles."</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Cancelar"</string>
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 49f3891..f418e34 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Seleccionar fondo de pantalla de"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Establecer fondo de pantalla"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Fondos de pantalla"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"La aplicación no está instalada en el teléfono."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"La aplicación no está instalada."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configurar..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Carpetas"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Más"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Fondos de pantalla"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Accesos directos de aplicaciones"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Será la carpeta de fondos de pantalla."</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Todas las aplicaciones"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplicaciones"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Juegos"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Descargadas"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"No hay juegos."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Sin aplicaciones descarg."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"No se puede soltar el elemento en este escritorio."</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Seleccionar widget"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nombre de carpeta"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Cambiar nombre de carpeta"</string>
<string name="rename_action" msgid="6016003384693240896">"Aceptar"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Seleccionar acceso directo"</string>
<string name="title_select_application" msgid="8031072293115454221">"Seleccionar aplicación"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Seleccionar carpeta"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Todas las aplicaciones"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplicaciones"</string>
<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="menu_add" msgid="3065046628354640854">"Añadir"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Administrar aplicaciones"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Fondo de pantalla"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notificaciones"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestos"</string>
<string name="menu_settings" msgid="6233960148378443661">"Ajustes"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Desinstalar aplicación"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Información de la aplicación"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Se ha seleccionado una aplicación."</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Se ha seleccionado un widget."</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Se ha seleccionado una carpeta."</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Se ha seleccionado un acceso directo."</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"instalar accesos directos"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Permite que una aplicación añada accesos directos sin intervención del usuario."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"desinstalar accesos directos"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"escribir información de accesos directos y de configuración del escritorio"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Permite que una aplicación modifique la configuración y los accesos directos de la página de inicio."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problema al cargar el widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Se trata de una aplicación del sistema y no se puede desinstalar."</string>
</resources>
diff --git a/res/values-fa-xlarge/strings.xml b/res/values-fa-xlarge/strings.xml
new file mode 100644
index 0000000..159cc4f
--- /dev/null
+++ b/res/values-fa-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"انتخاب تصویر زمینه"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"هیچ تصویر زمینه ای موجود نیست"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"لغو"</string>
+</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index a0fac1c..2c9afb2 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"انتخاب تصویر زمینه از"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"تنظیم تصویر زمینه"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"تصاویر زمینه"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"برنامه کاربردی در گوشی شما نصب نشد."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"برنامه نصب نشده است."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"پیکربندی..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"ابزارک ها"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"پوشه ها"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"بیشتر"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"تصاویر زمینه"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"میانبرهای برنامه کاربردی"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"این برگه تصاویر زمینه خواهد بود"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"همه"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"برنامه های کاربردی"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"بازی ها"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"دانلود شد"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"هیچ بازی پیدا نشد."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"هیچ برنامه دانلود شده ای پیدا نشد."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"نمی توان موردی در این صفحه اصلی انداخت"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"انتخاب ابزارک جهت ایجاد"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"نام پوشه"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"تغییر نام پوشه"</string>
<string name="rename_action" msgid="6016003384693240896">"تأیید"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"انتخاب میانبر"</string>
<string name="title_select_application" msgid="8031072293115454221">"انتخاب برنامه"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"انتخاب پوشه"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"همه برنامه های کاربردی"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"برنامه های کاربردی"</string>
<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="menu_add" msgid="3065046628354640854">"افزودن"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"مدیریت برنامه ها"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"تصویر زمینه"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"اعلان ها"</string>
<string name="menu_gestures" msgid="514678675575912237">"اشاره ها"</string>
<string name="menu_settings" msgid="6233960148378443661">"تنظیمات"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"حذف نصب برنامه"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"جزئیات برنامه کاربردی"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 برنامه انتخاب شد"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 ابزارک انتخاب شد"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 پوشه انتخاب شد"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 میانبر انتخاب شد"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"نصب میانبرها"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"به یک برنامه کاربردی اجازه می دهد میانبرها را بدون دخالت کاربر اضافه کند."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"حذف نصب میانبرها"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"نوشتن تنظیمات صفحه اصلی و میانبرها"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"به برنامه کاربردی اجازه می دهد تنظیمات و میانبرها را در صفحه اصلی تغییر دهد."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"مشکل در بارگیری ابزارک"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"این یک برنامه سیستمی است و لغو نصب نمی شود."</string>
</resources>
diff --git a/res/values-fi-xlarge/strings.xml b/res/values-fi-xlarge/strings.xml
new file mode 100644
index 0000000..7559e16
--- /dev/null
+++ b/res/values-fi-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Valitse taustakuva"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Ei taustakuvia saatavilla"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Peruuta"</string>
+</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index caec0b0..2f09924 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Valitse taustakuva valikosta"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Aseta taustakuva"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Taustakuvat"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Sovellusta ei ole asennettu puhelimeesi."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Sovellusta ei ole asennettu."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Määritä..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgetit"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Kansiot"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Lisää"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Taustakuvat"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Sovelluspikakuvakkeet"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Tämä on taustakuvavälilehti"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Kaikki"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Sovellukset"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Pelit"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Ladatut"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Ei pelejä."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Ei ladattuja sovelluksia."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Kohdetta ei voi lisätä etusivulle"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Valitse luotava widget"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Kansion nimi"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Nimeä kansio uudelleen"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Valitse pikakuvake"</string>
<string name="title_select_application" msgid="8031072293115454221">"Valitse sovellus"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Valitse kansio"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Kaikki sovellukset"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Sovellukset"</string>
<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="menu_add" msgid="3065046628354640854">"Lisää"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Hallinnoi sovelluksia"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Taustakuva"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Ilmoitukset"</string>
<string name="menu_gestures" msgid="514678675575912237">"Eleet"</string>
<string name="menu_settings" msgid="6233960148378443661">"Asetukset"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Poista sovellus"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Sovelluksen tiedot"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 sovellus valittu"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget valittu"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 kansio valittu"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 pikakuvake valittu"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"asentaa pikakuvakkeita"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Antaa sovelluksen lisätä pikakuvakkeita itsenäisesti ilman käyttäjän valintaa."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"poistaa pikakuvakkeita"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"kirjoittaa etusivun asetuksia ja pikakuvakkeita"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Antaa sovelluksen muuttaa etusivun asetuksia ja pikakuvakkeita."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Ongelma ladattaessa widgetiä"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Tämä on järjestelmäsovellus, eikä sitä voi poistaa."</string>
</resources>
diff --git a/res/values-fr-xlarge/strings.xml b/res/values-fr-xlarge/strings.xml
new file mode 100644
index 0000000..0c5d315
--- /dev/null
+++ b/res/values-fr-xlarge/strings.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Sélectionner un fond d\'écran"</string>
+ <!-- no translation found for wallpaper_chooser_empty (7358237455389125747) -->
+ <skip />
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Annuler"</string>
+</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 29c4c58..50f88a8 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Sélectionner à partir de..."</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Sélectionner"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Fonds d\'écran"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"L\'application n\'est pas installée sur votre téléphone."</string>
+ <!-- outdated translation 3571057450431950427 --> <string name="activity_not_found" msgid="5591731020063337696">"L\'application n\'est pas installée sur votre téléphone."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configurer..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Dossiers"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Plus"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Fonds d\'écran"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Raccourcis des applications"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Onglet des fonds d\'écran"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Toutes"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Applications"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Jeux"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Téléchargées"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Aucun jeu n\'a été trouvé."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Pas d\'application téléchargée"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Impossible de déposer l\'élément sur l\'écran d\'accueil."</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Sélectionner le widget à créer"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nom du dossier"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Renommer le dossier"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Sélectionner un raccourci"</string>
<string name="title_select_application" msgid="8031072293115454221">"Sélection d\'une application"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Sélectionner le dossier"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Toutes les applications"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Applications"</string>
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Page d\'accueil"</string>
+ <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Supprimer"</string>
+ <!-- outdated translation 2536335964588694907 --> <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Supprimer"</string>
<string name="menu_add" msgid="3065046628354640854">"Ajouter"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gérer les applications"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Fond d\'écran"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notifications"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestes"</string>
<string name="menu_settings" msgid="6233960148378443661">"Paramètres"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Désinstaller l\'application"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Infos sur l\'application"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 application sélectionnée"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget sélectionné"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 dossier sélectionné"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 raccourci sélectionné"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"installer des raccourcis"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Permet à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"désinstaller les raccourcis"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"Enregistrer les paramètres de la page d\'accueil et des raccourcis"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Permet à une application de modifier les paramètres et les raccourcis de la page d\'accueil."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problème lors du chargement du widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Il s\'agit d\'une application système que vous ne pouvez pas désinstaller."</string>
</resources>
diff --git a/res/values-hr-xlarge/strings.xml b/res/values-hr-xlarge/strings.xml
new file mode 100644
index 0000000..7e4a299
--- /dev/null
+++ b/res/values-hr-xlarge/strings.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Odaberite pozadinsku sliku"</string>
+ <!-- no translation found for wallpaper_chooser_empty (7358237455389125747) -->
+ <skip />
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Odustani"</string>
+</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 5645c54..fad275e 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Odabir između pozadinskih slika"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Postavi pozadinsku sliku"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Pozadinske slike"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Aplikacija nije instalirana na vašem telefonu."</string>
+ <!-- outdated translation 3571057450431950427 --> <string name="activity_not_found" msgid="5591731020063337696">"Aplikacija nije instalirana na vašem telefonu."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfiguriraj..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgeti"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mape"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Više"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Pozadinske slike"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Prečaci aplikacija"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Ovo će biti kartica pozadinske slike"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Sve"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplikacije"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Igre"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Preuzeto"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Igre nisu pronađene."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nema preuzetih aplikacija"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Nije bilo moguće spustiti stavku na početni zaslon"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Odabir widgeta za stvaranje"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Naziv mape"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Preimenuj mapu"</string>
<string name="rename_action" msgid="6016003384693240896">"U redu"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Odaberite prečac"</string>
<string name="title_select_application" msgid="8031072293115454221">"Odaberite aplikaciju"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Odaberite mapu"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Sve aplikacije"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplikacije"</string>
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Početna"</string>
+ <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Ukloni"</string>
+ <!-- outdated translation 2536335964588694907 --> <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Izbriši"</string>
<string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Upravljaj aplikacijama"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Pozadinska slika"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Obavijesti"</string>
<string name="menu_gestures" msgid="514678675575912237">"Geste"</string>
<string name="menu_settings" msgid="6233960148378443661">"Postavke"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Deinstaliraj aplikaciju"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Detalji aplikacije"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 aplikacija odabrana"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget odabran"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 mapa odabrana"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 prečac odabran"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"instaliraj prečace"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Dopušta aplikaciji dodavanje prečaca bez intervencije korisnika."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"deinstaliraj prečace"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"zapiši postavke početnog zaslona i prečaca"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Dopušta aplikaciji promjenu postavki i prečaca na početnom zaslonu."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problem pri učitavanju widgeta"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Ovo je aplikacija sustava i ne može se ukloniti."</string>
</resources>
diff --git a/res/values-hu-xlarge/strings.xml b/res/values-hu-xlarge/strings.xml
new file mode 100644
index 0000000..800581e
--- /dev/null
+++ b/res/values-hu-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Háttérkép kiválasztása"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Nincs elérhető háttérkép"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Mégse"</string>
+</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 53bf122..ff946de 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Háttérkép kiválasztása innen:"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Háttérkép beállítása"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Háttérképek"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Az alkalmazás már nincs telepítve a telefonján."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Az alkalmazás nincs telepítve."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurálás..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Modulok"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mappák"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Egyebek"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Háttérképek"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Alkalmazás-parancsikonok"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Ez lesz a háttérképek lapja"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Összes"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Alkalmazások"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Játékok"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Letöltött"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nincsenek játékok."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nincs letöltött alk."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Nem lehet elhelyezni az elemet ezen a főoldalon"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"A létrehozandó modul kiválasztása"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Mappa neve"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Mappa átnevezése"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Parancsikon kiválasztása"</string>
<string name="title_select_application" msgid="8031072293115454221">"Alkalmazás kiválasztása"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Mappa kiválasztása"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Minden alkalmazás"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Alkalmazások"</string>
<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="menu_add" msgid="3065046628354640854">"Hozzáadás"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Alkalmazások kezelése"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Háttérkép"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Értesítések"</string>
<string name="menu_gestures" msgid="514678675575912237">"Kézmozdulatok"</string>
<string name="menu_settings" msgid="6233960148378443661">"Beállítások"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Alkalmazás eltávolítása"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Alkalmazás részletei"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 alkalmazás kiválasztva"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 modul kiválasztva"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 mappa kiválasztva"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 parancsikon kiválasztva"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"parancsikonok telepítése"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül adjon hozzá parancsikonokat."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"parancsikonok eltávolítása"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"Főoldal beállításainak és parancsikonjainak írása"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Lehetővé teszi egy alkalmazás számára, hogy módosítsa a Főoldal beállításait és parancsikonjait."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Probléma történt a modul betöltésekor"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Ez egy rendszeralkalmazás, ezért nem lehet eltávolítani."</string>
</resources>
diff --git a/res/values-in-xlarge/strings.xml b/res/values-in-xlarge/strings.xml
new file mode 100644
index 0000000..7062353
--- /dev/null
+++ b/res/values-in-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Pilih wallpaper"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Tidak tersedia wallpaper"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Batal"</string>
+</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 4c2cf62..acecc43 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Pilih wallpaper dari"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Setel wallpaper"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Wallpaper"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Aplikasi tidak dipasang pada ponsel Anda."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Aplikasi tidak terpasang."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurasikan..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widget"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Map"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Lainnya"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Wallpaper"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Pintasan App"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Ini akan menjadi tab wallpaper"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Semua"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Apps"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Permainan"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Diunduh"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Tidak ditemukan permainan."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Tidak ada aplikasi yang diunduh."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Tidak dapat menaruh item pada layar utama ini"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Pilih widget untuk membuat"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nama map"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Ubah nama map"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Pilih pintasan"</string>
<string name="title_select_application" msgid="8031072293115454221">"Pilih aplikasi"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Pilih map"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Semua aplikasi"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Apps"</string>
<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="menu_add" msgid="3065046628354640854">"Tambahkan"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Mengelola aplikasi"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Wallpaper"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Pemberitahuan"</string>
<string name="menu_gestures" msgid="514678675575912237">"Isyarat"</string>
<string name="menu_settings" msgid="6233960148378443661">"Setelan"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Copot pemasangan aplikasi"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Detail aplikasi"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 aplikasi dipilih"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget dipilih"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 map dipilih"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 pintasan dipilih"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"pasang pintasan"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Mengizinkan aplikasi menambahkan pintasan tanpa tindakan dari pengguna."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"copot pemasangan pintasan"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"tuliskan setelan dan pintasan Beranda"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Mengizinkan aplikasi mengubah setelan dan pintasan dalam Beranda."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Masalah memuat widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Ini adalah aplikasi sistem dan tidak dapat diunduh."</string>
</resources>
diff --git a/res/values-it-xlarge/strings.xml b/res/values-it-xlarge/strings.xml
new file mode 100644
index 0000000..e667b75
--- /dev/null
+++ b/res/values-it-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Seleziona sfondo"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Nessuno sfondo disponibile"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Annulla"</string>
+</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 9f8db44..0c2ca9f 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Seleziona sfondo da"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Imposta sfondo"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Sfondi"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Applicazione non installata sul telefono."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Applicazione non installata."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configura..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widget"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Cartelle"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Altro"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Sfondi"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Scorciatoie applicazioni"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Questa sarà la scheda degli sfondi"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Tutte"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Applicazioni"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Giochi"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Scaricate"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nessun gioco trovato."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nessuna appl. scaricata"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Impossibile rilasciare elemento in schermata Home"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Seleziona il widget da creare"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nome cartella"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Rinomina cartella"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Seleziona scorciatoia"</string>
<string name="title_select_application" msgid="8031072293115454221">"Seleziona applicazione"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Seleziona cartella"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Tutte le applicazioni"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Applicazioni"</string>
<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="menu_add" msgid="3065046628354640854">"Aggiungi"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gestisci applicazioni"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Sfondo"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notifiche"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gesti"</string>
<string name="menu_settings" msgid="6233960148378443661">"Impostazioni"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Disinstalla applicazione"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Dettagli applicazione"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 applicazione selezionata"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget selezionato"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 cartella selezionata"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 scorciatoia selezionata"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"aggiungere scorciatoie"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Consente a un\'applicazione di aggiungere scorciatoie automaticamente."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"eliminare scorciatoie"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"creare impostazioni e scorciatoie in Home"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Consente a un\'applicazione di modificare le impostazioni e le scorciatoie in Home."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Errore durante il caricamento del widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Questa è un\'applicazione di sistema e non può essere disinstallata."</string>
</resources>
diff --git a/res/values-iw-xlarge/strings.xml b/res/values-iw-xlarge/strings.xml
new file mode 100644
index 0000000..72e6b0f
--- /dev/null
+++ b/res/values-iw-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"בחר טפט"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"אין טפטים זמינים"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"ביטול"</string>
+</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 44f8766..7ba83a7 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"בחר טפט מ"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"הגדר טפט"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"טפטים"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"היישום אינו מותקן בטלפון."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"היישום לא מותקן."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"הגדר..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"רכיבי Widget"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"תיקיות"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"עוד"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"טפטים"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"קיצורי דרך של יישומים"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"זו תהיה כרטיסיית הטפטים"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"הכל"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"יישומים"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"משחקים"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"ירדו"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"לא נמצאו משחקים."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"לא נמצאו יישומים שהורדו."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"אין אפשרות להניח פריט במסך בית זה"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"בחר widget כדי ליצור"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"שם תיקיה"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"שנה את שם התיקיה"</string>
<string name="rename_action" msgid="6016003384693240896">"אישור"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"בחר קיצור דרך"</string>
<string name="title_select_application" msgid="8031072293115454221">"בחר יישום"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"בחר תיקיה"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"כל היישומים"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"יישומים"</string>
<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="menu_add" msgid="3065046628354640854">"הוסף"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"נהל יישומים"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"טפט"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"התראות"</string>
<string name="menu_gestures" msgid="514678675575912237">"מחוות"</string>
<string name="menu_settings" msgid="6233960148378443661">"הגדרות"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"הסר התקנה של יישום"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"פרטי יישום"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"נבחר יישום אחד"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"נבחר widget אחד"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"נבחרה תיקיה אחת"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"נבחר קיצור דרך אחד"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"התקן קיצורי דרך"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"מאפשר ליישום להוסיף קיצורים ללא התערבות המשתמש."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"הסר קיצורי דרך"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"כתוב הגדרות וקיצורי דרך של דף הבית"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"מאפשר ליישום לשנות את ההגדרות וקיצורי הדרך בדף הבית."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"בעיה בטעינת widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"זהו יישום מערכת ואין אפשרות להסיר את התקנתו."</string>
</resources>
diff --git a/res/values-ja-xlarge/strings.xml b/res/values-ja-xlarge/strings.xml
new file mode 100644
index 0000000..85e3b6c
--- /dev/null
+++ b/res/values-ja-xlarge/strings.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"壁紙の選択"</string>
+ <!-- no translation found for wallpaper_chooser_empty (7358237455389125747) -->
+ <skip />
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"キャンセル"</string>
+</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index b401b8b..f44e9e5 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"壁紙を選択"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"壁紙に設定"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"壁紙"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"アプリケーションがインストールされていません。"</string>
+ <!-- outdated translation 3571057450431950427 --> <string name="activity_not_found" msgid="5591731020063337696">"アプリケーションがインストールされていません。"</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"設定..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"ウィジェット"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"フォルダ"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"その他"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"壁紙"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"アプリのショートカット"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"ここが壁紙タブになります"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"すべて"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"アプリ"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"ゲーム"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"ダウンロード済み"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"ゲームなし"</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"ダウンロードアプリなし"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"このホーム画面にアイテムをドロップできませんでした"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"作成するウィジェットを選択"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"フォルダ名"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"フォルダ名を変更"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"ショートカットを選択"</string>
<string name="title_select_application" msgid="8031072293115454221">"アプリを選択"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"フォルダの選択"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"すべてのアプリケーション"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"アプリ"</string>
<string name="all_apps_home_button_label" msgid="1022222300329398558">"ホーム"</string>
+ <string name="delete_zone_label_workspace" msgid="7153615831493049150">"削除"</string>
+ <!-- outdated translation 2536335964588694907 --> <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"削除"</string>
<string name="menu_add" msgid="3065046628354640854">"追加"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"アプリの管理"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"壁紙"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"通知"</string>
<string name="menu_gestures" msgid="514678675575912237">"ジェスチャー"</string>
<string name="menu_settings" msgid="6233960148378443661">"設定"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"アプリケーションのアンインストール"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"アプリケーションの詳細"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1つのアプリケーションが選択されています"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1つのウィジェットが選択されています"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1つのフォルダが選択されています"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1つのショートカットが選択されています"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"ショートカットのインストール"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"ユーザー操作なしでショートカットの追加をアプリケーションに許可します。"</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"ショートカットのアンインストール"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"ホームの設定とショートカットの書き込み"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"ホームの設定とショートカットの変更をアプリケーションに許可します。"</string>
<string name="gadget_error_text" msgid="8359351016167075858">"ウィジェットを表示できません"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"このシステムアプリケーションはアンインストールできません。"</string>
</resources>
diff --git a/res/values-ko-xlarge/strings.xml b/res/values-ko-xlarge/strings.xml
new file mode 100644
index 0000000..4c7e3c6
--- /dev/null
+++ b/res/values-ko-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"배경화면 선택"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"배경화면이 없습니다."</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"취소"</string>
+</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 8787589..3ccc4a7 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"배경화면 선택"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"배경화면 설정"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"배경화면"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"휴대전화에 설치되어 있지 않은 애플리케이션입니다."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"애플리케이션이 설치되지 않았습니다."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"구성..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"위젯"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"폴더"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"더보기"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"배경화면"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"앱 바로가기"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"배경화면 탭이 됩니다."</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"모두"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"애플리케이션"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"게임"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"다운로드앱"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"게임이 없습니다."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"다운로드한 애플리케이션이 없습니다."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"홈 화면에 항목을 드롭할 수 없습니다."</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"만들 위젯 선택"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"폴더 이름"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"폴더 이름 바꾸기"</string>
<string name="rename_action" msgid="6016003384693240896">"확인"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"바로가기 선택"</string>
<string name="title_select_application" msgid="8031072293115454221">"애플리케이션 선택"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"폴더 선택"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"모든 애플리케이션"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"애플리케이션"</string>
<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="menu_add" msgid="3065046628354640854">"추가"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"애플리케이션 관리"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"배경화면"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"알림"</string>
<string name="menu_gestures" msgid="514678675575912237">"동작"</string>
<string name="menu_settings" msgid="6233960148378443661">"설정"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"애플리케이션 제거"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"애플리케이션 세부정보"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1개 애플리케이션 선택"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1개 위젯 선택"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1개 폴더 선택"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1개 바로가기 선택"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"바로가기 설치"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"애플리케이션이 사용자의 작업 없이 바로가기를 추가할 수 있도록 합니다."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"바로가기 제거"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"홈 설정 및 바로가기 쓰기"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"애플리케이션이 홈에 있는 설정 및 바로가기를 변경할 수 있도록 합니다."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"위젯을 로드하는 중 문제가 발생했습니다."</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"시스템 애플리케이션은 제거할 수 없습니다."</string>
</resources>
diff --git a/res/values-lt-xlarge/strings.xml b/res/values-lt-xlarge/strings.xml
new file mode 100644
index 0000000..527a09b
--- /dev/null
+++ b/res/values-lt-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Pasirinkti darbalaukio foną"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Nepasiekiami jokie darbalaukio fonai"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Atšaukti"</string>
+</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 8f233e5..10727a7 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Pasirinkti darbalaukio foną iš"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Nustatyti darbalaukio foną"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Darbalaukio fonai"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Programa jūsų telefone neįdiegta."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Programa neįdiegta."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigūruoti..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Valdikliai"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Aplankai"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Daugiau"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Darbalaukio fonai"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Spartieji programos klavišai"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Tai bus darbalaukio fonų skirtukas"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Visos"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Apps"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Žaidimai"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Atsisiųsta"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nerasta žaidimų."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nerasta atsisiųstų progr."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Nepavyko pašalinti elemento šiame pagr. ekrane"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Pasirinkti norimą sukurti valdiklį"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Aplanko pavadinimas"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Sukurti aplankui naują pavadinimą"</string>
<string name="rename_action" msgid="6016003384693240896">"Gerai"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Pasirinkti spartųjį klavišą"</string>
<string name="title_select_application" msgid="8031072293115454221">"Pasirinkti programą"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Pasirinkti aplanką"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Visos programos"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Apps"</string>
<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="menu_add" msgid="3065046628354640854">"Pridėti"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Valdyti programas"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Darbalaukio fonas"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Įspėjimai"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestai"</string>
<string name="menu_settings" msgid="6233960148378443661">"Nustatymai"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Pašalinti programą"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Išsami programos informacija"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Pasirinkta 1 programa"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Pasirinktas 1 valdiklis"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Pasirinktas 1 aplankas"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Pasirinktas 1 spartusis klavišas"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"įdiegti sparčiuosius klavišus"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Leidžia programai pridėti sparčiuosius klavišus be naudotojo įsikišimo."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"pašalinti sparčiuosius klavišus"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"rašyti pagrindinio puslapio nustatymus ir sparčiuosius klavišus"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Leidžia programai keisti pagrindinio puslapio nustatymus ir sparčiuosius klavišus."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problema įkeliant valdiklį"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Tai sistemos programa ir jos negalima pašalinti."</string>
</resources>
diff --git a/res/values-lv-xlarge/strings.xml b/res/values-lv-xlarge/strings.xml
new file mode 100644
index 0000000..167ee7a
--- /dev/null
+++ b/res/values-lv-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Fona tapetes atlase"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Tapetes nav pieejamas."</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Atcelt"</string>
+</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 6c1a4c3..6cc70e7 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Atlasīt tapeti no"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Iestatīt tapeti"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Tapetes"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Lietojumprogramma jūsu tālrunī nav instalēta."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Lietojumprogramma nav instalēta."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurēt..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Logrīki"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mapes"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Vairāk"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Fona tapetes"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Lietotnes saīsnes"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Šī būs fona tapetes cilne"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Visas"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Lietotnes"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Spēles"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Lejupielād."</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nav nevienas spēles."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nav lejupiel. lietotņu."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Nevarēja nomest vienumu šajā sākumekrānā."</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Atlasīt izveidojamo logrīku"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Mapes nosaukums"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Mapes pārdēvēšana"</string>
<string name="rename_action" msgid="6016003384693240896">"Labi"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Saīsnes atlase"</string>
<string name="title_select_application" msgid="8031072293115454221">"Lietojumprogrammas atlase"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Mapes atlase"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Visas lietojumprogrammas"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Lietotnes"</string>
<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="menu_add" msgid="3065046628354640854">"Pievienot"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Lietotņu pārvaldība"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Fona tapete"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Paziņojumi"</string>
<string name="menu_gestures" msgid="514678675575912237">"Žesti"</string>
<string name="menu_settings" msgid="6233960148378443661">"Iestatījumi"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Atinstalēt lietojumprogrammu"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Lietojumprogrammas dati"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Atlasīta 1 lietojumprogramma"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Atlasīts 1 logrīks"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Atlasīta 1 mape"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Atlasīta 1 saīsne"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"ievietot saīsnes"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Ļauj lietojumprogrammai pievienot saīsnes, nejautājot lietotājam."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"atinstalēt saīsnes"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"rakstīt sākuma ekrāna iestatījumus un saīsnes"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Ļauj lietojumprogrammai mainīt iestatījumus un saīsnes sākuma ekrānā."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Radās problēma, ielādējot logrīku"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Šī ir sistēmas lietojumprogramma un to nevar atinstalēt."</string>
</resources>
diff --git a/res/values-nb-xlarge/strings.xml b/res/values-nb-xlarge/strings.xml
new file mode 100644
index 0000000..dd58eae
--- /dev/null
+++ b/res/values-nb-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Velg bakgrunnsbilde"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Ingen bakgrunner tilgjengelig"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Avbryt"</string>
+</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 201d2d0..a51be4b 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Velg bakgrunnsbilde fra"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Velg bakgrunnsbilde"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Bakgrunner"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Applikasjonen er ikke installert."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Programmet er ikke installert."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurer"</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Moduler"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mapper"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Mer"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Bakgrunner"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Programsnarveier"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Dette er nå bakgrunnsfanen"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Alle"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Programmer"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Spill"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Nedlastet"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Finner ingen spill."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Finner ingen nedl.prog."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Kunne ikke slippe elementet på denne startskjermen"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Velg modul for oppretting"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Mappenavn"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Gi nytt navn til mappe"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Velg snarvei"</string>
<string name="title_select_application" msgid="8031072293115454221">"Velg program"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Velg mappe"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Alle programmer"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Programmer"</string>
<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="menu_add" msgid="3065046628354640854">"Legg til"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Administrer programmer"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Bakgrunnsbilde"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Varslinger"</string>
<string name="menu_gestures" msgid="514678675575912237">"Bevegelser"</string>
<string name="menu_settings" msgid="6233960148378443661">"Innstillinger"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Avinstaller program"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Søknadsopplysninger"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 program valgt"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 modul valgt"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 mappe valgt"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 snarvei valgt"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"installere snarveier"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Lar applikasjonen legge til snarveier uten å involvere brukeren."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"avinstallere snarveier"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"skrive skrivebordsinnstillinger og -snarveier"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Lar applikasjonen endre innstillinger og snarveier på skrivebordet."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problem under lasting av gadget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Dette er et systemprogram og kan ikke avinstalleres."</string>
</resources>
diff --git a/res/values-nl-xlarge/strings.xml b/res/values-nl-xlarge/strings.xml
new file mode 100644
index 0000000..474f13b
--- /dev/null
+++ b/res/values-nl-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Achtergrond selecteren"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Geen achtergronden beschikbaar"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Annuleren"</string>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 389e893..7de43a4 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Achtergrond selecteren in"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Achtergrond instellen"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Achtergronden"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Deze toepassing is niet geïnstalleerd op uw telefoon."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"De toepassing is niet geïnstalleerd."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configureren..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mappen"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Meer"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Achtergronden"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Toepassingssnelkoppelingen"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Dit wordt het tabblad \'Achtergronden\'"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Alle"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Toepassingen"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Games"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Gedownload"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Geen games gevonden."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Geen gedownl. apps gevond."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Kan item niet neerzetten op dit startscherm"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Widget selecteren om te maken"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Mapnaam"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Naam van map wijzigen"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Snelkoppeling selecteren"</string>
<string name="title_select_application" msgid="8031072293115454221">"Toepassing selecteren"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Map selecteren"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Alle toepassingen"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Toepassingen"</string>
<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="menu_add" msgid="3065046628354640854">"Toevoegen"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Toepassingen beheren"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Achtergrond"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Meldingen"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gebaren"</string>
<string name="menu_settings" msgid="6233960148378443661">"Instellingen"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Toepassing verwijderen"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Toepassingsdetails"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 toepassing geselecteerd"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget geselecteerd"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 map geselecteerd"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 snelkoppeling geselecteerd"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"snelkoppelingen installeren"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Een toepassing toestaan om snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"snelkoppelingen verwijderen"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"instellingen en snelkoppelingen voor de startpagina schrijven"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Hiermee kan een toepassing de instellingen en snelkoppelingen op de startpagina wijzigen."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Probleem bij het laden van widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Dit is een systeemtoepassing die niet kan worden verwijderd."</string>
</resources>
diff --git a/res/values-pl-xlarge/strings.xml b/res/values-pl-xlarge/strings.xml
new file mode 100644
index 0000000..51b2442
--- /dev/null
+++ b/res/values-pl-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Wybierz tapetę"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Brak tapet"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Anuluj"</string>
+</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 019a016..e3a98ab 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Wybierz tapetę"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Ustaw tapetę"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Tapety"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Aplikacja nie jest zainstalowana w telefonie."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Aplikacja nie jest zainstalowana."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfiguruj..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widżety"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Foldery"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Więcej"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Tapety"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Skróty do aplikacji"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"To będzie karta tapet"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Wszystkie"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplikacje"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Gry"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Pobrane"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nie znaleziono gier."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Brak pobranych aplikacji."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Nie można upuścić elementu na ekranie głównym"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Wybierz widżet do utworzenia"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nazwa folderu"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Zmień nazwę folderu"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Wybierz skrót"</string>
<string name="title_select_application" msgid="8031072293115454221">"Wybierz aplikację"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Wybierz folder"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Wszystkie aplikacje"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplikacje"</string>
<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="menu_add" msgid="3065046628354640854">"Dodaj"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Zarządzaj aplikacjami"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Tapeta"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Powiadomienia"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gesty"</string>
<string name="menu_settings" msgid="6233960148378443661">"Ustawienia"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Odinstaluj aplikację"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Szczegóły aplikacji"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Zaznaczono 1 aplikację"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Zaznaczono 1 widżet"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Zaznaczono 1 folder"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Zaznaczono 1 skrót"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"zainstaluj skróty"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Umożliwia aplikacji dodawanie skrótów bez interwencji użytkownika."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"odinstaluj skróty"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"zapisywanie ustawień i skrótów strony głównej"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Umożliwia aplikacji zmianę ustawień i skrótów strony głównej."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problem podczas ładowania widżetu"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"To jest aplikacja systemowa i nie można jej odinstalować."</string>
</resources>
diff --git a/res/values-pt-rPT-xlarge/strings.xml b/res/values-pt-rPT-xlarge/strings.xml
new file mode 100644
index 0000000..9ec0e0f
--- /dev/null
+++ b/res/values-pt-rPT-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Seleccionar imagem de fundo"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Nenhuma imagem de fundo disponível"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Cancelar"</string>
+</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 73bf895..5b25e4a 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Seleccionar imagem de fundo a partir de"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Definir imagem de fundo"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Imagens de fundo"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"A aplicação não está instalada no telefone."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"A aplicação não está instalada."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configurar..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Pastas"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Mais"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Imagens de fundo"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Atalhos de aplicações"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Isto será o separador de imagens de fundo"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Todas"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplicações"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Jogos"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Transferidas"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Sem jogos."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Sem aplic. transferidas."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Não foi possível largar o item neste ecrã inicial"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Seleccionar widget a criar"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nome da pasta"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Mudar o nome da pasta"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Seleccione o atalho"</string>
<string name="title_select_application" msgid="8031072293115454221">"Seleccionar aplicação"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Seleccione a pasta"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Todas as aplicações"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplicações"</string>
<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="menu_add" msgid="3065046628354640854">"Adicionar"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gerir aplicações"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Imagem de fundo"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notificações"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestos"</string>
<string name="menu_settings" msgid="6233960148378443661">"Definições"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Desinstalar aplicação"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Detalhes da aplicação"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 aplicação seleccionada"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget seleccionado"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 pasta seleccionada"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 atalho seleccionado"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"instalar atalhos"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Permite que uma aplicação adicione atalhos sem a intervenção do utilizador."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"desinstalar atalhos"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"escrever definições e atalhos do ecrã principal"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Permite que uma aplicação altere as definições e os atalhos do ecrã principal."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Erro ao carregar o widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"É uma aplicação de sistema e não pode ser desinstalada."</string>
</resources>
diff --git a/res/values-pt-xlarge/strings.xml b/res/values-pt-xlarge/strings.xml
new file mode 100644
index 0000000..2f98ec2
--- /dev/null
+++ b/res/values-pt-xlarge/strings.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Selecionar plano de fundo"</string>
+ <!-- no translation found for wallpaper_chooser_empty (7358237455389125747) -->
+ <skip />
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Cancelar"</string>
+</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 33cde96..d2d2eab 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -25,13 +25,27 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Selecionar plano de fundo de"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Definir plano de fundo"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Papéis de parede"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"O aplicativo não está instalado no seu telefone."</string>
+ <!-- outdated translation 3571057450431950427 --> <string name="activity_not_found" msgid="5591731020063337696">"O aplicativo não está instalado no seu telefone."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configurar..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgets"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Pastas"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Mais"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Papéis de parede"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Atalhos de aplicativo"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Esta será a guia de papéis de parede"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Todos"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplicativos"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Jogos"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Download concluído"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nenhum jogo encontrado."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nenhum aplic. encontrado."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Não foi possível soltar o item nesta tela inicial"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Selecione um widget para criar"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nome da pasta"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Renomear pasta"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
<string name="cancel_action" msgid="3811860427489435048">"Cancelar"</string>
- <string name="menu_item_add_item" msgid="6233177331075781114">"Adicionar à tela inicial"</string>
+ <string name="menu_item_add_item" msgid="6233177331075781114">"Adicionar à tela da Página inicial"</string>
<string name="group_applications" msgid="4118484163419674240">"Aplicativos"</string>
<string name="group_shortcuts" msgid="9133529424900391877">"Atalhos"</string>
<string name="group_folder" msgid="5143593791798929193">"Nova pasta"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Selecionar atalho"</string>
<string name="title_select_application" msgid="8031072293115454221">"Selecionar aplicativo"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Selecionar pasta"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Todos os aplicativos"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplicativos"</string>
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Página inicial"</string>
+ <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remover"</string>
+ <!-- outdated translation 2536335964588694907 --> <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Excluir"</string>
<string name="menu_add" msgid="3065046628354640854">"Adicionar"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gerenciar aplicativos"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Plano de fundo"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notificações"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestos"</string>
<string name="menu_settings" msgid="6233960148378443661">"Configurações"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Desinstalar aplicativo"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Detalhes do aplicativo"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Um aplicativo selecionado"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Um widget selecionado"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Uma pasta selecionada"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Um atalho selecionado"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"instalar atalhos"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Permite que um aplicativo adicione os atalhos sem a intervenção do usuário."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"desinstalar atalhos"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"gravar configurações e atalhos da Página inicial"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Permite que um aplicativo altere as configurações e atalhos na Página inicial."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problema ao carregar o widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Este é um aplicativo do sistema e não pode ser desinstalado."</string>
</resources>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index 67ae450..182327c 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -25,8 +25,36 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Tscherner in fund davos"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Definir in fund davos"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Maletgs da fund davos"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"L\'applicaziun n\'è betg installada sin quest telefonin."</string>
+ <!-- outdated translation 3571057450431950427 --> <string name="activity_not_found" msgid="5591731020063337696">"L\'applicaziun n\'è betg installada sin quest telefonin."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configurar…"</string>
+ <!-- no translation found for widgets_tab_label (9145860100000983599) -->
+ <skip />
+ <!-- no translation found for folders_tab_label (1145293785541489736) -->
+ <skip />
+ <!-- no translation found for shortcuts_tab_label (8640731503933155644) -->
+ <skip />
+ <!-- no translation found for wallpapers_tab_label (1617804870364119879) -->
+ <skip />
+ <!-- no translation found for applications_tab_label (9046797126882613707) -->
+ <skip />
+ <!-- no translation found for wallpapers_temp_tab_text (1660218201190495279) -->
+ <skip />
+ <!-- no translation found for all_apps_tab_all (2942727589595027258) -->
+ <skip />
+ <!-- no translation found for all_apps_tab_apps (5468972551904071712) -->
+ <skip />
+ <!-- no translation found for all_apps_tab_games (1855736784923494918) -->
+ <skip />
+ <!-- no translation found for all_apps_tab_downloaded (3335316755603669951) -->
+ <skip />
+ <!-- no translation found for all_apps_no_games (5293893733372793696) -->
+ <skip />
+ <!-- no translation found for all_apps_no_downloads (2284720393234453761) -->
+ <skip />
+ <!-- no translation found for external_drop_widget_error (4976816434597126575) -->
+ <skip />
+ <!-- no translation found for external_drop_widget_pick_title (4481311720134376218) -->
+ <skip />
<string name="rename_folder_label" msgid="5646236631298452787">"Num da l\'ordinatur"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Renumnar l\'ordinatur"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -49,8 +77,12 @@
<!-- no translation found for title_select_application (8031072293115454221) -->
<skip />
<string name="title_select_live_folder" msgid="3753447798805166749">"Tscherner l\'ordinatur"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Tut las applicaziuns"</string>
+ <!-- outdated translation 3953036962111614813 --> <string name="all_apps_button_label" msgid="2578400570124163469">"Tut las applicaziuns"</string>
<string name="all_apps_home_button_label" msgid="1022222300329398558">"Pagina da partenza"</string>
+ <!-- no translation found for delete_zone_label_workspace (7153615831493049150) -->
+ <skip />
+ <!-- no translation found for delete_zone_label_all_apps (6664588234817475108) -->
+ <skip />
<string name="menu_add" msgid="3065046628354640854">"Agiuntar"</string>
<!-- no translation found for menu_manage_apps (2308685199463588895) -->
<skip />
@@ -59,6 +91,18 @@
<string name="menu_notifications" msgid="6424587053194766192">"Avis"</string>
<string name="menu_gestures" msgid="514678675575912237">"Moviments"</string>
<string name="menu_settings" msgid="6233960148378443661">"Parameters"</string>
+ <!-- no translation found for cab_menu_delete_app (1242619904941293871) -->
+ <skip />
+ <!-- no translation found for cab_menu_app_info (5180426909324882018) -->
+ <skip />
+ <!-- no translation found for cab_app_selection_text (606113924828167756) -->
+ <skip />
+ <!-- no translation found for cab_widget_selection_text (962527270506951955) -->
+ <skip />
+ <!-- no translation found for cab_folder_selection_text (8916111874189565067) -->
+ <skip />
+ <!-- no translation found for cab_shortcut_selection_text (8115847384500412878) -->
+ <skip />
<string name="permlab_install_shortcut" msgid="1201690825493376489">"Installar scursanidas"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Pussibilitescha ch\'ina applicaziun agiunta scursanidas senza l\'intervenziun da l\'utilisader."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"deinstallar scursanidas"</string>
@@ -68,4 +112,6 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"Definir ils parameters e las scursanidas per la pagina da partenza"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Pussibilitescha ch\'ina applicaziun possia midar ils parameters e las scursanidas sin la pagina da partenza."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problems cun chargiar il widget"</string>
+ <!-- no translation found for uninstall_system_app_text (7488523163288397451) -->
+ <skip />
</resources>
diff --git a/res/values-ro-xlarge/strings.xml b/res/values-ro-xlarge/strings.xml
new file mode 100644
index 0000000..6bea7b5
--- /dev/null
+++ b/res/values-ro-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Selectaţi o imagine de fundal"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Nu există imagini de fundal disponibile"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Anulaţi"</string>
+</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 05d5754..185192f 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Selectaţi imaginea de fundal din"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Setaţi imaginea de fundal"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Imagini de fundal"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Aplicaţia nu este instalată pe telefonul dvs."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Aplicaţia nu este instalată."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Configuraţi..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Obiecte widget"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Dosare"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Mai multe"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Imagini de fundal"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Comenzi rapide aplicaţii"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Aceasta va fi fila pentru imagini de fundal"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Toate"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplicaţii"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Jocuri"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Descărcate"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nu s-au găsit jocuri."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Nu s-au găsit apl. desc."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Impos. de plasat elem. pe acest ecran de pornire"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Selectaţi obiectul widget"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Nume dosar"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Redenumiţi dosarul"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Selectaţi comanda rapidă"</string>
<string name="title_select_application" msgid="8031072293115454221">"Selectaţi aplicaţia"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Selectaţi dosarul"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Toate aplicaţiile"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplicaţii"</string>
<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="menu_add" msgid="3065046628354640854">"Adăugaţi"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Gestionaţi aplicaţii"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Imagine de fundal"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Notificări"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gesturi"</string>
<string name="menu_settings" msgid="6233960148378443661">"Setări"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Dezinstalaţi aplicaţia"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Detalii aplicaţie"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 aplicaţie selectată"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 obiect widget selectat"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 dosar selectat"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 comandă rapidă selectată"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"instalaţi comenzi rapide"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Permite unei aplicaţii să adauge comenzi rapide, fără intervenţia utilizatorului."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"dezinstalaţi comenzile rapide"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"scrieţi setări şi comenzi rapide pentru Ecranul de pornire"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Permite unei aplicaţii să modifice setările şi comenzile rapide pentru Ecranul de pornire."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Probleme la încărcarea obiectului widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Aceasta este o aplicaţie a sistemului şi nu se poate dezinstala."</string>
</resources>
diff --git a/res/values-ru-xlarge/strings.xml b/res/values-ru-xlarge/strings.xml
new file mode 100644
index 0000000..01796bc
--- /dev/null
+++ b/res/values-ru-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Выберите обои"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Нет доступных обоев"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Отмена"</string>
+</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 973e173..f32579a 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Выбрать обои из:"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Установить обои"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Обои"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Приложение не установлено на телефоне."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Приложение не установлено."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Настроить..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Виджеты"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Папки"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Ещё"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Обои"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Ярлыки приложений"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Это будет вкладка обоев"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Все"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Приложения"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Игры"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Загруженные"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Игр не найдено."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Нет загруженных приложений."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Не удается скопировать элемент на главный экран"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Выберите виджет"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Название папки"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Переименовать папку"</string>
<string name="rename_action" msgid="6016003384693240896">"ОК"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Выберите ярлык"</string>
<string name="title_select_application" msgid="8031072293115454221">"Выбор приложения"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Выбор папки"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Все приложения"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Приложения"</string>
<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="menu_add" msgid="3065046628354640854">"Добавить"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Приложения"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Обои"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Уведомления"</string>
<string name="menu_gestures" msgid="514678675575912237">"Жесты"</string>
<string name="menu_settings" msgid="6233960148378443661">"Настройки"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Удалить приложение"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Сведения о приложении"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Выбрано 1 приложение"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Выбран 1 виджет"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Выбрана 1 папка"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Выбран 1 ярлык"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"устанавливать ярлыки"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Позволяет приложению добавлять ярлыки без вмешательства пользователя"</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"удалять ярлыки"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"изменять настройки и ярлыки главного экрана"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Позволяет приложению изменять настройки и ярлыки на главном экране."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Не удалось загрузить виджет"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Это системное приложение. Удалить его невозможно."</string>
</resources>
diff --git a/res/values-sk-xlarge/strings.xml b/res/values-sk-xlarge/strings.xml
new file mode 100644
index 0000000..c857c3c
--- /dev/null
+++ b/res/values-sk-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Výber tapety"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Tapety nie sú k dispozícii"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Zrušiť"</string>
+</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index d3ea5c2..3962fbd 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Vybrať tapetu z priečinka"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Nastaviť tapetu"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Tapety"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Aplikácia nie je v telefóne nainštalovaná."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Aplikácia nie je nainštalovaná."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurovať..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Miniaplikácie"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Priečinky"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Viac"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Tapety"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Odkazy aplikácií"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Toto bude karta Tapety"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Všetky"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Aplikácie"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Hry"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Prevzaté"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Nenašli sa žiadne hry."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Žiadne prevz. aplikácie."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Položku sa nepodarilo pretiahnuť na túto plochu"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Vyberte miniaplikáciu"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Názov priečinka"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Premenovať priečinok"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Vyberte odkaz"</string>
<string name="title_select_application" msgid="8031072293115454221">"Výber aplikácie"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Vyberte priečinok"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Všetky aplikácie"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Aplikácie"</string>
<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="menu_add" msgid="3065046628354640854">"Pridať"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Spravovať aplikácie"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Tapeta"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Upozornenia"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gestá"</string>
<string name="menu_settings" msgid="6233960148378443661">"Nastavenia"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Odinštalovať aplikáciu"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Podrobnosti o aplikácii"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Vybratá 1 aplikácia"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Vybratá 1 miniaplikácia"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Vybratý 1 priečinok"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Vybratý 1 odkaz"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"inštalovať odkazy"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Povoľuje aplikácii pridať odkaz bez zásahu používateľa."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"odinštalovať odkazy"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"zápis nastavení a odkazov plochy"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Povoľuje aplikácii zmeniť nastavenia a odkazy plochy."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problém s načítaním miniaplikácií"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Toto je systémová aplikácia a nie je možné ju odinštalovať."</string>
</resources>
diff --git a/res/values-sl-xlarge/strings.xml b/res/values-sl-xlarge/strings.xml
new file mode 100644
index 0000000..f007b98
--- /dev/null
+++ b/res/values-sl-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Izberite sliko za ozadje"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Ni slik za ozadje"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Prekliči"</string>
+</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index cdcaed8..12ff463 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Izberi sliko za ozadje iz"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Nastavi sliko za ozadje"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Slike za ozadje"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Program ni nameščen v telefonu."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Program ni nameščen."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfiguriraj ..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Pripomočki"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mape"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Več"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Ozadja"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Bližnjice do programov"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"To bo zavihek ozadij"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Vse"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Programi"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Igre"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Preneseno"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Ni najdenih iger."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Ni najdenih prenesenih programov."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Elementa ni bilo mogoče postaviti na ta začetni zaslon"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Izberite želeni pripomoček"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Ime mape"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Preimenuj mapo"</string>
<string name="rename_action" msgid="6016003384693240896">"V redu"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Izberi bližnjico"</string>
<string name="title_select_application" msgid="8031072293115454221">"Izberite program"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Izberite mapo"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Vsi programi"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Programi"</string>
<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="menu_add" msgid="3065046628354640854">"Dodaj"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Upravljaj programe"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Slika za ozadje"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Obvestila"</string>
<string name="menu_gestures" msgid="514678675575912237">"Poteze"</string>
<string name="menu_settings" msgid="6233960148378443661">"Nastavitve"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Odstrani program"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Podrobnosti o programu"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Izbran je 1 program"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Izbran je 1 pripomoček"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Izbrana je 1 mapa"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Izbrana je 1 bližnjica"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"namesti bližnjice"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Omogoča programu dodajanje bližnjic brez posredovanja uporabnika."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"odstrani bližnjice"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"zapis nastavitev in bližnjic začetnega zaslona"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Omogoča programu spreminjanje nastavitev in bližnjic na začetnem zaslonu."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Težave pri nalaganju pripomočka"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"To je sistemski program in ga ni mogoče odstraniti."</string>
</resources>
diff --git a/res/values-sr-xlarge/strings.xml b/res/values-sr-xlarge/strings.xml
new file mode 100644
index 0000000..f716909
--- /dev/null
+++ b/res/values-sr-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Избор позадине"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Позадине нису доступне"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Откажи"</string>
+</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 138f691..12f637e 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Избор позадине из"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Подеси позадину"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Позадине"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Апликација није инсталирана у телефону."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Апликација није инсталирана."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Конфигурисање..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Виџети"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Директоријуми"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Још"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Позадине"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Пречице за апликације"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Ово ће бити картица позадине"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Све"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Apps"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Игре"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Преузето"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Нису пронађене игре."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Нису пронађене преузете апликације"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Ставка није пребачена на овај почетни екран"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Изаберите виџет за креирање"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Име директоријума"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Преименовање директоријума"</string>
<string name="rename_action" msgid="6016003384693240896">"Потврди"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Избор пречице"</string>
<string name="title_select_application" msgid="8031072293115454221">"Изаберите апликацију"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Избор директоријума"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Све апликације"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Apps"</string>
<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="menu_add" msgid="3065046628354640854">"Додај"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Управљање апликацијама"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Позадина"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Обавештења"</string>
<string name="menu_gestures" msgid="514678675575912237">"Покрети"</string>
<string name="menu_settings" msgid="6233960148378443661">"Подешавања"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Деинсталирај апликацију"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Детаљи о апликацији"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Изабрана је 1 апликација"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Изабран је 1 виџет"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Изабран је 1 директоријум"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Изабрана је 1 пречица"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"инсталирај пречице"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Омогућава апликацији да дода пречице без интервенције корисника."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"деинсталирај пречице"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"уписивање подешавања и пречица на почетном екрану"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Омогућава апликацији да промени подешавања и пречице на почетном екрану."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Проблем приликом учитавања виџета"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Ово је системска апликација и не може да се деинсталира."</string>
</resources>
diff --git a/res/values-sv-xlarge/strings.xml b/res/values-sv-xlarge/strings.xml
new file mode 100644
index 0000000..907348a
--- /dev/null
+++ b/res/values-sv-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Välj bakgrund"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Inga tillgängliga bakgrundsbilder"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Avbryt"</string>
+</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 079a141..7d54842 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Välj bakgrund från"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Ange bakgrund"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Bakgrundsbilder"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Programmet är inte installerat på din telefon."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Appen är inte installerad."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Konfigurera..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widgetar"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mappar"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Mer"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Bakgrundsbilder"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Genvägar för appar"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Det här kommer att vara fliken för bakgrundsbilder"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Alla"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Program"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Spel"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Hämtade"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Inga spel hittades."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Inga hämtade appar."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Objektet kunde inte släppas på den här startsidan"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Välj en widget att skapa"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Mappnamn"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Byt namn på mapp"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Välj genväg"</string>
<string name="title_select_application" msgid="8031072293115454221">"Välj program"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Välj mapp"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Alla program"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Program"</string>
<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="menu_add" msgid="3065046628354640854">"Lägg till"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Hantera appar"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Bakgrund"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Aviseringar"</string>
<string name="menu_gestures" msgid="514678675575912237">"Gester"</string>
<string name="menu_settings" msgid="6233960148378443661">"Inställningar"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Avinstallera program"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Programinformation"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 program har valts"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget vald"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 mapp vald"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 genväg har valts"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"installera genvägar"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Tillåter att ett program lägger till genvägar utan åtgärd från användaren."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"avinstallera genvägar"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"skriva inställningar och genvägar för startsidan"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Tillåter att ett program ändrar inställningar och genvägar på startsidan."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Det gick inte att läsa in widgeten"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Det här är ett systemprogram och kan inte avinstalleras."</string>
</resources>
diff --git a/res/values-th-xlarge/strings.xml b/res/values-th-xlarge/strings.xml
new file mode 100644
index 0000000..38c7d85
--- /dev/null
+++ b/res/values-th-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"เลือกวอลเปเปอร์"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"ไม่มีวอลเปเปอร์ให้ใช้งาน"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"ยกเลิก"</string>
+</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 4445147..c2795bb 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"เลือกวอลเปเปอร์จาก"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"ตั้งค่าวอลเปเปอร์"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"วอลเปเปอร์"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"ไม่ได้ติดตั้งแอปพลิเคชันบนโทรศัพท์ของคุณ"</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"ไม่ได้ติดตั้งแอปพลิเคชัน"</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"กำหนดค่า..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"วิดเจ็ต"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"โฟลเดอร์"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"เพิ่มเติม"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"วอลเปเปอร์"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"ทางลัดของแอปพลิเคชัน"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"นี่จะเป็นแท็บวอลเปเปอร์"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"ทั้งหมด"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"แอปพลิเคชัน"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"เกม"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"ที่ดาวน์โหลดไว้"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"ไม่พบเกม"</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"ไม่พบแอปพลิเคชันที่ดาวน์โหลดไว้"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"ไม่สามารถวางรายการลงในหน้าจอหลักนี้ได้"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"เลือกวิดเจ็ตที่จะสร้าง"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"ชื่อโฟลเดอร์"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"เปลี่ยนชื่อโฟลเดอร์"</string>
<string name="rename_action" msgid="6016003384693240896">"ตกลง"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"เลือกทางลัด"</string>
<string name="title_select_application" msgid="8031072293115454221">"เลือกแอปพลิเคชัน"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"เลือกโฟลเดอร์"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"แอปพลิเคชันทั้งหมด"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"แอปพลิเคชัน"</string>
<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="menu_add" msgid="3065046628354640854">"เพิ่ม"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"จัดการแอปพลิเคชัน"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"วอลเปเปอร์"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"การแจ้งเตือน"</string>
<string name="menu_gestures" msgid="514678675575912237">"ท่าทาง"</string>
<string name="menu_settings" msgid="6233960148378443661">"การตั้งค่า"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"ถอนการติดตั้งแอปพลิเคชัน"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"รายละเอียดแอปพลิเคชัน"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"เลือก 1 แอปพลิเคชัน"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"เลือก 1 วิดเจ็ต"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"เลือก 1 โฟลเดอร์"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"เลือก 1 ทางลัด"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"ติดตั้งทางลัด"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"อนุญาตให้แอปพลิเคชันเพิ่มทางลัดโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"ถอนการติดตั้งทางลัด"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"เขียนการตั้งค่าและทางลัดหน้าแรกแล้ว"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"อนุญาตให้แอปพลิเคชันเปลี่ยนการตั้งค่าและทางลัดในหน้าแรก"</string>
<string name="gadget_error_text" msgid="8359351016167075858">"มีปัญหาขณะโหลดวิดเจ็ต"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"นี่เป็นแอปพลิเคชันระบบและไม่สามารถถอนการติดตั้งได้"</string>
</resources>
diff --git a/res/values-tl-xlarge/strings.xml b/res/values-tl-xlarge/strings.xml
new file mode 100644
index 0000000..7eadb6d
--- /dev/null
+++ b/res/values-tl-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Pumili ng wallpaper"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Walang available na mga wallpaper"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Kanselahin"</string>
+</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 7eeba88..c92cf30 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Pumili ng wallpaper mula sa"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Itakda ang wallpaper"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Mga Wallpaper"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Hindi naka-install ang application sa iyong telepono."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Hindi na-install ang application"</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"I-configure..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Mga Widget"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Mga Folder"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Higit pa"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Mga Wallpaper"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Mga Shortcut ng App"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Ito ang magiging tab ng mga wallpaper"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Lahat"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Apps"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Mga Laro"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Na-download"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Walang nakitang mga laro."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Walang na-download na app"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Hindi ma-drop ang item sa homescreen na ito"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Pumili ng widget na lilikhain"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Pangalan ng folder"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Palitan ng pangalan ang folder"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Pumili ng shortcut"</string>
<string name="title_select_application" msgid="8031072293115454221">"Pumili ng application"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Pumili ng folder"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Lahat ng mga application"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Apps"</string>
<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="menu_add" msgid="3065046628354640854">"Idagdag"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Pamahalaan ang apps"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Wallpaper"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Mga Notification"</string>
<string name="menu_gestures" msgid="514678675575912237">"Mga Gesture"</string>
<string name="menu_settings" msgid="6233960148378443661">"Mga Setting"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"I-uninstall ang application"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Mga detalye ng application"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 application ang napili"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget ang napili"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 folder ang napili"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 shortcut ang napili"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"i-install ang mga shortcut"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Pinapayagan ang isang application na magdagdag ng mga shortcut nang walang panghihimasok ng user."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"huwag i-install ang mga shortcut"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"magsulat ng mga setting ng Home at mga shortcut"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Pinapayagan ang isang application na baguhin ang mga setting at shortcut sa Home."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Problema sa pag-load ng widget"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Isa itong system application at hindi maaaring i-install."</string>
</resources>
diff --git a/res/values-tr-xlarge/strings.xml b/res/values-tr-xlarge/strings.xml
new file mode 100644
index 0000000..a81e998
--- /dev/null
+++ b/res/values-tr-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Duvar kağıdı seçin"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Hiç duvar kağıdı yok"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"İptal"</string>
+</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 3e23c32..4b35afc 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Buradan duvar kağıdını seçin:"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Duvar kağıdını ayarla"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Duvar Kağıtları"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Uygulama telefonunuza yüklenmemiş."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Uygulama yüklü değil."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Yapılandır..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Widget\'lar"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Klasörler"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Diğer"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Duvar Kağıtları"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Uygulama Kısayolları"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Bu duvar kağıdı sekmesi olacaktır"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Tümü"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Uygulamalar"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Oyunlar"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"İndirilenler"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Oyun bulunamadı."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"İndirilmş uyg bulunamadı."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Öğe bu ana ekrana bırakılamadı"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Oluşturulacak widget\'i seç"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Klasör adı"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Klasörü yeniden adlandır"</string>
<string name="rename_action" msgid="6016003384693240896">"Tamam"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Kısayolu seçin"</string>
<string name="title_select_application" msgid="8031072293115454221">"Uygulama seç"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Klasörü seçin"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Tüm uygulamalar"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Uygulamalar"</string>
<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="menu_add" msgid="3065046628354640854">"Ekle"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Uyglm yönet"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Duvar Kağıdı"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Bildirimler"</string>
<string name="menu_gestures" msgid="514678675575912237">"Hareketler"</string>
<string name="menu_settings" msgid="6233960148378443661">"Ayarlar"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Uygulamanın yüklemesini kaldır"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Uygulama ayrıntıları"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"1 uygulama seçildi"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget seçildi"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 klasör seçildi"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 kısayol seçildi"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"kısayolları yükle"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Bir uygulamaya, kısayolları kullanıcı müdahale etmeden ekleme izni verir."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"kısayolları kaldır"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"Ana Sayfa ayarlarını ve kısayollarını yaz"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Bir uygulamaya Ana Sayfadaki ayarları ve kısayolları değiştirme izni verir."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Widget yüklenirken sorun oluştu"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Bu bir sistem uygulamasıdır ve kaldırılamaz."</string>
</resources>
diff --git a/res/values-uk-xlarge/strings.xml b/res/values-uk-xlarge/strings.xml
new file mode 100644
index 0000000..7c859cb
--- /dev/null
+++ b/res/values-uk-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Вибрати фоновий малюнок"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Фонові малюнки не доступні"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Скасувати"</string>
+</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 6a10970..0a1c79e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Установ. фон. мал. з"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Устан. фон. мал."</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Фонові мал."</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Програму не встановлено у вашому телефоні."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Програму не встановлено."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Налаштувати..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Віджети"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Папки"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Більше"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Фонові мал."</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Ярлики програм"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"This will be the wallpapers tab"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Усі"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Програми"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Ігри"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Завантажені"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Ігор не знайдено."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Завантаж. прог. не знайд."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Неможливо помістити елемент на цей головний екран"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Вибрати віджет для створення"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Назва папки"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Переймен. папку"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Вибрати ярлик"</string>
<string name="title_select_application" msgid="8031072293115454221">"Вибрати програму"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Виберіть папку"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Усі програми"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Прогр."</string>
<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="menu_add" msgid="3065046628354640854">"Додати"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Керув. прогр."</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Фоновий мал."</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Сповіщення"</string>
<string name="menu_gestures" msgid="514678675575912237">"Жести"</string>
<string name="menu_settings" msgid="6233960148378443661">"Налаштув-ня"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Видалити програму"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Деталі програми"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Вибрано 1 програму"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Вибрано 1 віджет"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Вибрано 1 папку"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Вибрано 1 ярлик"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"установити ярлики"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Дозволяє програмі додавати ярлики без утручання користувача."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"видалити ярлики"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"писати налашт-ня Головної та ярлики"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Дозволяє програмі змінювати налаштування та ярлики на Головній."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Пробл із завантаж. віджета"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Це системна програма, її неможливо видалити."</string>
</resources>
diff --git a/res/values-vi-xlarge/strings.xml b/res/values-vi-xlarge/strings.xml
new file mode 100644
index 0000000..9257327
--- /dev/null
+++ b/res/values-vi-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"Chọn hình nền"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"Không có sẵn hình nền nào"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"Hủy"</string>
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index bd2f2ec..eff426e 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"Chọn hình nền từ"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"Đặt hình nền"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"Hình nền"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"Ứng dụng chưa được cài đặt trên điện thoại của bạn."</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"Ứng dụng chưa được cài đặt."</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"Định cấu hình..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"Tiện ích"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"Thư mục"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"Khác"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"Hình nền"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"Lối tắt ứng dụng"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"Đây sẽ là tab hình nền"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"Tất cả"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"Ứng dụng"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"Trò chơi"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"Đã tải xuống"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"Không tìm thấy trò chơi."</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"Không tìm thấy ư.dụng được t.xuống."</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"Không thể thả mục vào màn hình chính này"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"Chọn tiện ích để tạo"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"Tên thư mục"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"Đổi tên thư mục"</string>
<string name="rename_action" msgid="6016003384693240896">"OK"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"Chọn lối tắt"</string>
<string name="title_select_application" msgid="8031072293115454221">"Chọn ứng dụng"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"Chọn thư mục"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"Tât cả ứng dụng"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"Ứng dụng"</string>
<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="menu_add" msgid="3065046628354640854">"Thêm"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"Quản lý ứng dụng"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"Hình nền"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"Thông báo"</string>
<string name="menu_gestures" msgid="514678675575912237">"Cử chỉ"</string>
<string name="menu_settings" msgid="6233960148378443661">"Cài đặt"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"Gỡ cài đặt ứng dụng"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"Chi tiết ứng dụng"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"Đã chọn 1 ứng dụng"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"Đã chọn 1 tiện ích"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"Đã chọn 1 thư mục"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"Đã chọn 1 lối tắt"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"cài đặt lối tắt"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"Cho phép ứng dụng thêm lối tắt mà không cần sự can thiệp của người dùng."</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"gỡ cài đặt lối tắt"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"ghi cài đặt Màn hình trang chủ và lối tắt"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"Cho phép ứng dụng thay đổi cài đặt và lối tắt trên Màn hình trang chủ."</string>
<string name="gadget_error_text" msgid="8359351016167075858">"Sự cố khi tải tiện ích"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"Đây là ứng dụng hệ thống và không thể gỡ cài đặt."</string>
</resources>
diff --git a/res/values-xlarge-land/dimens.xml b/res/values-xlarge-land/dimens.xml
new file mode 100644
index 0000000..51037f5
--- /dev/null
+++ b/res/values-xlarge-land/dimens.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<resources>
+ <!-- the area at the edge of the screen that makes the workspace go left
+ or right while you're dragging. -->
+ <dimen name="scroll_zone">100dip</dimen>
+
+ <!-- Width/height gap overrides for the workspace -->
+ <dimen name="workspace_width_gap">32dp</dimen>
+ <dimen name="workspace_height_gap">2dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/res/values-xlarge-port/dimens.xml b/res/values-xlarge-port/dimens.xml
new file mode 100644
index 0000000..baa31aa
--- /dev/null
+++ b/res/values-xlarge-port/dimens.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<resources>
+ <!-- the area at the edge of the screen that makes the workspace go left
+ or right while you're dragging. -->
+ <dimen name="scroll_zone">40dp</dimen>
+
+ <!-- Width/height gap overrides for the workspace -->
+ <dimen name="workspace_width_gap">0dp</dimen>
+ <dimen name="workspace_height_gap">32dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml
new file mode 100644
index 0000000..3e514fb
--- /dev/null
+++ b/res/values-xlarge/config.xml
@@ -0,0 +1,83 @@
+<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">800</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">600</integer>
+
+ <!-- Scaling factor used in the all apps zooming animations -->
+ <integer name="config_allAppsZoomScaleFactor">10</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_customizeZoomInTime">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>
+
+ <!-- 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_allAppsCameraPanTime">700</integer>
+ <integer name="config_allAppsFadeOutTime">150</integer>
+ <integer name="config_customizeWorkspaceShrinkTime">800</integer>
+ <integer name="config_allAppsWorkspaceShrinkTime">800</integer>
+ <integer name="config_workspaceUnshrinkTime">450</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">100</integer>
+ <integer name="config_toolbarButtonFadeOutTime">100</integer>
+
+ <!-- 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 -->
+ <integer name="config_screenOnDropScalePercent">120</integer>
+ <integer name="config_screenOnDropScaleUpDuration">200</integer>
+ <integer name="config_screenOnDropScaleDownDuration">200</integer>
+ <integer name="config_screenOnDropAlphaFadeDelay">350</integer>
+ <integer name="config_screenOnDropAlphaFadeDuration">50</integer>
+
+ <!-- Workspace screens are cached to bitmaps only when they're smaller than a certain size
+ (maxScaleForUsingWorkspaceScreenBitmapCache), since the bitmap cache itself is smaller
+ than the view itself (workspaceScreenBitmapCacheScale) -->
+ <integer name="config_workspaceScreenBitmapCacheScale">20</integer>
+ <integer name="config_maxScaleForUsingWorkspaceScreenBitmapCache">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-xlarge/dimens.xml b/res/values-xlarge/dimens.xml
new file mode 100644
index 0000000..22f4134
--- /dev/null
+++ b/res/values-xlarge/dimens.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <dimen name="workspace_cell_width">96dip</dimen>
+ <dimen name="workspace_cell_height">96dip</dimen>
+
+ <!-- Width/height gap overrides for the workspace -->
+ <dimen name="workspace_width_gap">0dp</dimen>
+ <dimen name="workspace_height_gap">0dp</dimen>
+
+ <!-- The corner radius to draw the external drop icon rounded rect -->
+ <dimen name="external_drop_icon_rect_radius">10dp</dimen>
+
+ <!-- Size of icons in workspace -->
+ <dimen name="app_icon_size">72dp</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>
+
+ <!-- Vertical spacing between edge of screen and mini cell layouts when they
+ are minimized to the top when the customization drawer is showing -->
+ <dimen name="customizeSmallScreenVerticalMarginLandscape">90dip</dimen>
+ <dimen name="customizeSmallScreenVerticalMarginPortrait">180dip</dimen>
+
+ <dimen name="all_apps_drawable_padding">8dip</dimen>
+ <!-- toolbar divider height is 32dip plus 2*8dip for padding on top and bottom -->
+ <dimen name="toolbar_divider_height">48dip</dimen>
+ <dimen name="toolbar_button_vertical_padding">8dip</dimen>
+ <dimen name="toolbar_button_horizontal_padding">16dip</dimen>
+
+ <!-- height & width of the drop rectangle for the trash icon -->
+ <dimen name="delete_zone_vertical_drag_padding">20dip</dimen>
+ <dimen name="delete_zone_horizontal_drag_padding">20dip</dimen>
+
+ <!-- dimensions for the wallpaper picker wallpaper thumbnail width -->
+ <dimen name="wallpaper_chooser_grid_width">196dp</dimen>
+ <dimen name="wallpaper_chooser_grid_height">140dp</dimen>
+ <dimen name="live_wallpaper_grid_item_padding">8dip</dimen>
+
+ <!-- live_wallpaper_grid_item_width + 2 * live_wallpaper_grid_item_padding-->
+ <dimen name="live_wallpaper_column_width">212dip</dimen>
+
+ <!-- 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>
+</resources>
diff --git a/res/values-xlarge/strings.xml b/res/values-xlarge/strings.xml
new file mode 100644
index 0000000..75a22a2
--- /dev/null
+++ b/res/values-xlarge/strings.xml
@@ -0,0 +1,29 @@
+<?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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Title of the wallpaper selection dialog [CHAR_LIMIT=40]-->
+ <string name="wallpaper_dialog_title">Select wallpaper</string>
+
+ <!-- Text to show when there are no wallpapers [CHAR_LIMIT=40]-->
+ <string name="wallpaper_chooser_empty">No wallpapers available</string>
+
+ <!-- Negative button text for the wallpaper selection dialog [CHAR_LIMIT=40]-->
+ <string name="wallpaper_cancel">Cancel</string>
+</resources>
\ No newline at end of file
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
new file mode 100644
index 0000000..7208d97
--- /dev/null
+++ b/res/values-xlarge/styles.xml
@@ -0,0 +1,44 @@
+<?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.
+*/
+-->
+
+<resources>
+ <style name="Theme.WallpaperPicker" parent="android:Theme.Holo.Dialog.NoFrame">
+ </style>
+
+ <style name="Theme" parent="android:Theme.Holo">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowActionModeOverlay">true</item>
+
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="android:windowShowWallpaper">true</item>
+ </style>
+
+ <style name="WorkspaceIcon.Portrait">
+ <item name="android:drawablePadding">2dip</item>
+ <item name="android:paddingTop">0dip</item>
+ <item name="android:includeFontPadding">false</item>
+ </style>
+
+ <style name="WorkspaceIcon.Landscape">
+ <item name="android:drawablePadding">2dip</item>
+ <item name="android:paddingTop">0dip</item>
+ <item name="android:includeFontPadding">false</item>
+ </style>
+</resources>
diff --git a/res/values-xlarge/wallpapers.xml b/res/values-xlarge/wallpapers.xml
new file mode 100644
index 0000000..33c964b
--- /dev/null
+++ b/res/values-xlarge/wallpapers.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<resources>
+ <string-array name="wallpapers" translatable="false">
+ <item>glow_wallpaper</item>
+ <item>city_wallpaper</item>
+ </string-array>
+</resources>
diff --git a/res/values-zh-rCN-xlarge/strings.xml b/res/values-zh-rCN-xlarge/strings.xml
new file mode 100644
index 0000000..da36470
--- /dev/null
+++ b/res/values-zh-rCN-xlarge/strings.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"选择壁纸"</string>
+ <!-- no translation found for wallpaper_chooser_empty (7358237455389125747) -->
+ <skip />
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"取消"</string>
+</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 41ffac3..eb7b2e7 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"选择壁纸来源"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"设置壁纸"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"壁纸"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"您的手机上未安装应用程序。"</string>
+ <!-- outdated translation 3571057450431950427 --> <string name="activity_not_found" msgid="5591731020063337696">"您的手机上未安装应用程序。"</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"配置..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"窗口小部件"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"文件夹"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"更多"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"壁纸"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"应用程序快捷方式"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"这将会成为壁纸标签"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"全部"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"应用程序"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"游戏"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"已下载"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"未找到游戏。"</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"未找到已下载的应用程序。"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"无法将该项放到主屏幕上"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"选择窗口小部件进行创建"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"文件夹名称"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"重命名文件夹"</string>
<string name="rename_action" msgid="6016003384693240896">"确定"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"选择快捷方式"</string>
<string name="title_select_application" msgid="8031072293115454221">"选择应用程序"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"选择文件夹"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"所有应用程序"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"应用程序"</string>
<string name="all_apps_home_button_label" msgid="1022222300329398558">"主屏幕"</string>
+ <string name="delete_zone_label_workspace" msgid="7153615831493049150">"删除"</string>
+ <!-- outdated translation 2536335964588694907 --> <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"删除"</string>
<string name="menu_add" msgid="3065046628354640854">"添加"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"管理应用程序"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"壁纸"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"通知"</string>
<string name="menu_gestures" msgid="514678675575912237">"手势"</string>
<string name="menu_settings" msgid="6233960148378443661">"设置"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"卸载应用程序"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"应用程序详细信息"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"已选中 1 个应用程序"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"已选中 1 个窗口小部件"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"已选中 1 个文件夹"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"已选中 1 个快捷方式"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"安装快捷方式"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"允许应用程序在没有用户介入的情况下添加快捷方式。"</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"卸载快捷方式"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"写入主屏幕的设置和快捷方式"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"允许应用程序更改主屏幕的设置和快捷方式。"</string>
<string name="gadget_error_text" msgid="8359351016167075858">"载入窗口小部件时出现问题"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"这是系统应用程序,无法卸载。"</string>
</resources>
diff --git a/res/values-zh-rTW-xlarge/strings.xml b/res/values-zh-rTW-xlarge/strings.xml
new file mode 100644
index 0000000..793b58d
--- /dev/null
+++ b/res/values-zh-rTW-xlarge/strings.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wallpaper_dialog_title" msgid="5764793286524787718">"選取桌布"</string>
+ <string name="wallpaper_chooser_empty" msgid="7358237455389125747">"沒有可用的桌布"</string>
+ <string name="wallpaper_cancel" msgid="6502936522490675611">"取消"</string>
+</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 41566b2..171ab05 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -25,8 +25,22 @@
<string name="chooser_wallpaper" msgid="5988031014201479733">"從…選取桌布"</string>
<string name="wallpaper_instructions" msgid="4215640646180727542">"設定桌布"</string>
<string name="pick_wallpaper" msgid="5630222540525626723">"桌布"</string>
- <string name="activity_not_found" msgid="3571057450431950427">"應用程式未安裝到手機。"</string>
+ <string name="activity_not_found" msgid="5591731020063337696">"尚未安裝應用程式。"</string>
<string name="configure_wallpaper" msgid="2820186271419674623">"設定..."</string>
+ <string name="widgets_tab_label" msgid="9145860100000983599">"小工具"</string>
+ <string name="folders_tab_label" msgid="1145293785541489736">"資料夾"</string>
+ <string name="shortcuts_tab_label" msgid="8640731503933155644">"更多選項"</string>
+ <string name="wallpapers_tab_label" msgid="1617804870364119879">"桌布"</string>
+ <string name="applications_tab_label" msgid="9046797126882613707">"應用程式捷徑"</string>
+ <string name="wallpapers_temp_tab_text" msgid="1660218201190495279">"桌布標籤保留位"</string>
+ <string name="all_apps_tab_all" msgid="2942727589595027258">"全部"</string>
+ <string name="all_apps_tab_apps" msgid="5468972551904071712">"應用程式"</string>
+ <string name="all_apps_tab_games" msgid="1855736784923494918">"遊戲"</string>
+ <!-- outdated translation 2300935549064726963 --> <string name="all_apps_tab_downloaded" msgid="3335316755603669951">"下載內容"</string>
+ <string name="all_apps_no_games" msgid="5293893733372793696">"找不到遊戲。"</string>
+ <!-- outdated translation 6145042636084482299 --> <string name="all_apps_no_downloads" msgid="2284720393234453761">"找不到已下載的應用程式。"</string>
+ <string name="external_drop_widget_error" msgid="4976816434597126575">"無法將項目拖放至主螢幕上"</string>
+ <string name="external_drop_widget_pick_title" msgid="4481311720134376218">"選取要建立的小工具"</string>
<string name="rename_folder_label" msgid="5646236631298452787">"資料夾名稱"</string>
<string name="rename_folder_title" msgid="4544573104191526550">"重新命名資料夾"</string>
<string name="rename_action" msgid="6016003384693240896">"確定"</string>
@@ -48,8 +62,10 @@
<string name="title_select_shortcut" msgid="2858897527672831763">"選取捷徑"</string>
<string name="title_select_application" msgid="8031072293115454221">"選取應用程式"</string>
<string name="title_select_live_folder" msgid="3753447798805166749">"選取資料夾"</string>
- <string name="all_apps_button_label" msgid="3953036962111614813">"所有應用程式"</string>
+ <string name="all_apps_button_label" msgid="2578400570124163469">"應用程式"</string>
<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="menu_add" msgid="3065046628354640854">"新增"</string>
<string name="menu_manage_apps" msgid="2308685199463588895">"管理應用程式"</string>
<string name="menu_wallpaper" msgid="5837429080911269832">"桌布"</string>
@@ -57,6 +73,12 @@
<string name="menu_notifications" msgid="6424587053194766192">"通知"</string>
<string name="menu_gestures" msgid="514678675575912237">"觸控動作"</string>
<string name="menu_settings" msgid="6233960148378443661">"設定"</string>
+ <string name="cab_menu_delete_app" msgid="1242619904941293871">"解除安裝應用程式"</string>
+ <string name="cab_menu_app_info" msgid="5180426909324882018">"應用程式詳細資料"</string>
+ <string name="cab_app_selection_text" msgid="606113924828167756">"已選取 1 個應用程式"</string>
+ <string name="cab_widget_selection_text" msgid="962527270506951955">"已選取 1 個小工具"</string>
+ <string name="cab_folder_selection_text" msgid="8916111874189565067">"已選取 1 個資料夾"</string>
+ <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"已選取 1 個捷徑"</string>
<string name="permlab_install_shortcut" msgid="1201690825493376489">"安裝捷徑"</string>
<string name="permdesc_install_shortcut" msgid="7429365847558984148">"允許應用程式自動新增快速鍵。"</string>
<string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"解除安裝捷徑"</string>
@@ -66,4 +88,5 @@
<string name="permlab_write_settings" msgid="1360567537236705628">"寫入主螢幕設定和捷徑"</string>
<string name="permdesc_write_settings" msgid="1098648778383349818">"允許應用程式變更主螢幕中的設定和捷徑。"</string>
<string name="gadget_error_text" msgid="8359351016167075858">"載入小工具時發生問題"</string>
+ <string name="uninstall_system_app_text" msgid="7488523163288397451">"這是系統應用程式,無法將其解除安裝。"</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 7839120..5e6a2ab 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -32,6 +32,10 @@
<declare-styleable name="Workspace">
<!-- The first screen the workspace should display. -->
<attr name="defaultScreen" format="integer" />
+ <!-- The number of horizontal cells in the CellLayout -->
+ <attr name="cellCountX" format="integer" />
+ <!-- The number of vertical cells in the CellLayout -->
+ <attr name="cellCountY" format="integer" />
</declare-styleable>
<!-- CellLayout specific attributes. These attributes are used to customize
@@ -42,17 +46,67 @@
<!-- The height of a single cell -->
<attr name="cellHeight" format="dimension" />
<!-- Padding to apply at the start of the long axis -->
- <attr name="longAxisStartPadding" format="dimension" />
+ <attr name="xAxisStartPadding" format="dimension" />
<!-- Padding to apply at the end of the long axis -->
- <attr name="longAxisEndPadding" format="dimension" />
+ <attr name="xAxisEndPadding" format="dimension" />
<!-- Padding to apply at the start of the short axis -->
- <attr name="shortAxisStartPadding" format="dimension" />
+ <attr name="yAxisStartPadding" format="dimension" />
<!-- Padding to apply at the end of the short axis -->
- <attr name="shortAxisEndPadding" format="dimension" />
- <!-- Number of cells on the short axis of the CellLayout -->
- <attr name="shortAxisCells" format="integer" />
- <!-- Number of cells on the long axis of the CellLayout -->
- <attr name="longAxisCells" format="integer" />
+ <attr name="yAxisEndPadding" format="dimension" />
+ <!-- An override for the width and height gap to allow users to specify
+ a specific size for the page using spacing instead of resolving the
+ spacing from the width of the page -->
+ <attr name="widthGap" format="dimension" />
+ <attr name="heightGap" format="dimension" />
+
+ </declare-styleable>
+
+ <!-- PagedViewIcon specific attributes. These attributes are used to customize
+ a PagedViewIcon view in XML files. -->
+ <declare-styleable name="PagedViewIcon">
+ <!-- The blur color of the holographic outline -->
+ <attr name="blurColor" format="color" />
+ <!-- The outline color of the holographic outline -->
+ <attr name="outlineColor" format="color" />
+ </declare-styleable>
+
+ <!-- PagedViewWidget specific attributes. These attributes are used to
+ customize a PagedViewWidget view in XML files. -->
+ <declare-styleable name="PagedViewWidget">
+ <!-- The blur color of the holographic outline -->
+ <attr name="blurColor" />
+ <!-- The outline color of the holographic outline -->
+ <attr name="outlineColor" />
+ </declare-styleable>
+
+ <!-- PagedView specific attributes. These attributes are used to customize
+ a PagedView view in XML files. -->
+ <declare-styleable name="PagedView">
+ <!-- The number of horizontal cells in a page -->
+ <attr name="cellCountX" />
+ <!-- The number of vertical cells in a page -->
+ <attr name="cellCountY" />
+ <!-- A spacing override for the icons within a page -->
+ <attr name="pageLayoutWidthGap" format="dimension" />
+ <attr name="pageLayoutHeightGap" format="dimension" />
+ <!-- The padding of the pages that are dynamically created per page -->
+ <attr name="pageLayoutPaddingTop" format="dimension" />
+ <attr name="pageLayoutPaddingBottom" format="dimension" />
+ <attr name="pageLayoutPaddingLeft" format="dimension" />
+ <attr name="pageLayoutPaddingRight" format="dimension" />
+ <!-- The space between adjacent pages of the PagedView. -->
+ <attr name="pageSpacing" format="dimension" />
+ </declare-styleable>
+
+ <!-- CustomizePagedView specific attributes. These attributes are used to customize
+ a CustomizePagedView view in XML files. -->
+ <declare-styleable name="CustomizePagedView">
+ <!-- The cell span of an item in the wallpapers tab -->
+ <attr name="wallpaperCellSpanX" format="integer" />
+ <!-- The max cell span of all items in a particular wallpaper tab page -->
+ <attr name="wallpaperCellCountX" format="integer" />
+ <!-- The number of horizontal cells for the widget tab -->
+ <attr name="widgetCellCountX" format="integer" />
</declare-styleable>
<!-- DeleteZone specific attributes. These attributes are used to customize
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 9b9700f..91fe2c9 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -20,7 +20,7 @@
<resources>
<color name="window_background">#FF191919</color>
<color name="grid_dark_background">#EB191919</color>
- <color name="bubble_dark_background">#B2191919</color>
+ <color name="bubble_dark_background">#20000000</color>
<color name="delete_color_filter">#A5FF0000</color>
<color name="appwidget_error_color">#FCCC</color>
@@ -28,4 +28,18 @@
<color name="gesture_color">#ff0563c1</color>
<color name="uncertain_gesture_color">#ff848484</color>
+
+ <color name="app_info_filter">#A50000FE</color>
+ <color name="dimmed_view_color">#FF7F7F7F</color>
+
+ <color name="drag_outline_color">#9DBE12</color>
+
+ <color name="workspace_item_pressed_outline_color">#6595f9</color>
+ <color name="workspace_item_pressed_glow_color">#0997ff</color>
+ <color name="workspace_item_focused_outline_color">#6595f9</color>
+ <color name="workspace_item_focused_glow_color">#0997ff</color>
+
+ <color name="workspace_all_apps_and_delete_zone_text_color">#CCFFFFFF</color>
+ <color name="workspace_all_apps_and_delete_zone_text_shadow_color">#A0000000</color>
+ <color name="workspace_delete_zone_drag_text_color">#FFFF0000</color>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 15ec05b..473ed58 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -3,4 +3,37 @@
<integer name="config_allAppsFadeOutTime">700</integer>
<integer name="config_allAppsBatchLoadDelay">0</integer>
<integer name="config_allAppsBatchSize">0</integer>
+ <bool name="config_hardwareAccelerated">false</bool>
+
+ <integer name="config_crosshairsFadeInTime">600</integer>
+
+ <!-- When dragging an item 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">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>
+
+ <!-- The alpha value at which to show the most recent drop visualization outline. -->
+ <integer name="config_dragOutlineMaxAlpha">128</integer>
+
+ <!-- Parameters controlling the animation for when an item is dropped on the home screen,
+ and it animates from its old position to the new one. -->
+
+ <integer name="config_dropAnimMaxDuration">400</integer>
+
+ <!-- The distance at which the animation should take the max duration -->
+ <integer name="config_dropAnimMaxDist">800</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 c83986b..d6cd3ee 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -32,6 +32,9 @@
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>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a3df221..0c4aa26 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -39,10 +39,54 @@
<string name="wallpaper_instructions">Set wallpaper</string>
<!-- Option in "Select wallpaper from" dialog box -->
<string name="pick_wallpaper">Wallpapers</string>
- <!-- Displayed when user selects a shortcut for an app that was uninstalled -->
- <string name="activity_not_found">Application is not installed on your phone.</string>
+ <!-- Displayed when user selects a shortcut for an app that was uninstalled [CHAR_LIMIT=none]-->
+ <string name="activity_not_found">Application is not installed.</string>
<!-- List item for configuring the current wallpaper -->
<string name="configure_wallpaper">Configure...</string>
+ <!-- Labels for the tabs in the customize drawer -->
+ <string name="widgets_tab_label">Widgets</string>
+ <!-- Title of tab containing all possible folders (ie standard Folders and Live Folders) that
+ can be added to the home screen -->
+ <string name="folders_tab_label">Folders</string>
+ <!-- Title of tab containing all possible shortcuts (eg Contacts, Bookmarks) that can be
+ added to the home screen -->
+ <string name="shortcuts_tab_label">More</string>
+ <!-- Title of tab for configuring wallpapers -->
+ <string name="wallpapers_tab_label">Wallpapers</string>
+ <!-- Title of tab for configuring applications -->
+ <string name="applications_tab_label">App Shortcuts</string>
+ <!-- Placeholder text, will be removed -->
+ <string name="wallpapers_temp_tab_text">This will be the wallpapers tab</string>
+ <!-- Labels for the tabs in All Apps -->
+ <!-- Title of the tab for all applications (includes games and non-games) [CHAR_LIMIT=12] -->
+ <string name="all_apps_tab_all">All</string>
+ <!-- Title of the tab for all applications *except* games [CHAR_LIMIT=24] -->
+ <string name="all_apps_tab_apps">Apps</string>
+ <!-- Title of the tab for applications labeled as games [CHAR_LIMIT=24] -->
+ <string name="all_apps_tab_games">Games</string>
+ <!-- Tile of the tab for applications that were downloaded from market [CHAR_LIMIT=24] -->
+ <string name="all_apps_tab_downloaded">My Apps</string>
+
+ <!-- All Apps pane -->
+ <!-- Message to show when there are no games [CHAR_LIMIT=25] -->
+ <string name="all_apps_no_games">No games found.</string>
+ <!-- Message to show when there are no downloaded apps [CHAR_LIMIT=50] -->
+ <string name="all_apps_no_downloads">You have no downloaded applications.</string>
+
+ <!-- Customization Drawer -->
+ <!-- The format string for the dimensions of a widget in the drawer -->
+ <string name="widget_dims_format" translatable="false">%1$d x %2$d</string>
+
+ <!-- External-drop widget pick label format string [CHAR_LIMIT=25] -->
+ <string name="external_drop_widget_pick_format" translatable="false">%1$s (%2$d x %3$d)</string>
+ <!-- External-drop widget error string. This is the error that is shown
+ when you drag and item into the homescreen and it is unable to fit,
+ or an error is encountered. [CHAR_LIMIT=50] -->
+ <string name="external_drop_widget_error">Could not drop item onto this homescreen</string>
+ <!-- External-drop widget pick title. This is shown as the title of the
+ dialog which allows you to pick which widgets to handle a particular
+ drop if there are multiple choices. [CHAR_LIMIT=35] -->
+ <string name="external_drop_widget_pick_title">Select widget to create</string>
<!-- Folders -->
<skip />
@@ -93,11 +137,17 @@
<!-- Title of dialog when user is selecting live folder to add to homescreen -->
<string name="title_select_live_folder">Select folder</string>
- <!-- All applications label for accessibilty (spoken when the button gets focus). -->
- <string name="all_apps_button_label">All applications</string>
+ <!-- All applications label -->
+ <string name="all_apps_button_label">Apps</string>
<!-- Label for button in all applications label to go back home (to the workspace / desktop)
for accessibilty (spoken when the button gets focus). -->
<string name="all_apps_home_button_label">Home</string>
+ <!-- Label for trash icon on workspace. Meant to communicate the idea of removing the
+ icon/widget from the home screen, but not permanently. [CHAR_LIMIT=30] -->
+ <string name="delete_zone_label_workspace">Remove</string>
+ <!-- Label for trash icon in All Apps. The icon/widget will become completely unavailable on the
+ device. [CHAR_LIMIT=30]-->
+ <string name="delete_zone_label_all_apps">Uninstall</string>
<!-- Menus items: -->
<skip />
@@ -116,6 +166,23 @@
<!-- Noun, menu item used to show the system settings -->
<string name="menu_settings">Settings</string>
+ <!-- Strings for the contextual action bar (CAB) in All Apps -->
+ <skip />
+ <!-- Describes the button for uninstalling the currently selected application.
+ Text is not displayed, but provided for accessibility. [CHAR_LIMIT=none] -->
+ <string name="cab_menu_delete_app">Uninstall application</string>
+ <!-- Describes the button for getting details/info about currently selected application.
+ Text is not displayed, but provided for accessibility. [CHAR_LIMIT=none] -->
+ <string name="cab_menu_app_info">Application details</string>
+ <!-- Appears in the CAB when an app is selected in All Apps or Customize mode. [CHAR_LIMIT=50] -->
+ <string name="cab_app_selection_text">1 application selected</string>
+ <!-- Appears in the CAB when a widget is selected in Customize mode. [CHAR_LIMIT=50] -->
+ <string name="cab_widget_selection_text">1 widget selected</string>
+ <!-- Appears in the CAB when a folder is selected in Customize mode. [CHAR_LIMIT=50] -->
+ <string name="cab_folder_selection_text">1 folder selected</string>
+ <!-- Appears in the CAB when a shortcut is selected in Customize mode. [CHAR_LIMIT=50] -->
+ <string name="cab_shortcut_selection_text">1 shortcut selected</string>
+
<!-- Permissions: -->
<skip />
<!-- Permission short label -->
@@ -151,4 +218,6 @@
<string name="default_browser_url" translatable="false">
http://www.google.com/m?client=ms-{CID}&source=android-home-hotseat</string>
+ <!-- Text to inform the user that they can't uninstall a system application -->
+ <string name="uninstall_system_app_text">This is a system application and cannot be uninstalled.</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index c208211..7592a15 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -18,7 +18,14 @@
-->
<resources>
- <style name="Theme" parent="android:Theme.Wallpaper">
+ <style name="Theme.WallpaperPicker" parent="android:Theme">
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
+ <style name="Theme.Base" parent="android:Theme.Wallpaper">
+ </style>
+
+ <style name="Theme" parent="Theme.Base">
<item name="android:windowNoTitle">true</item>
</style>
@@ -31,17 +38,20 @@
<item name="android:textSize">13dip</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">marquee</item>
- <item name="android:shadowColor">#FF000000</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:background">@drawable/shortcut_selector</item>
<item name="android:paddingLeft">5dip</item>
<item name="android:paddingRight">5dip</item>
</style>
+ <style name="WorkspaceIcon.AllApps">
+ <item name="android:background">@null</item>
+ </style>
+
<style name="WorkspaceIcon.Portrait">
<item name="android:drawablePadding">5dip</item>
<item name="android:paddingTop">4dip</item>
diff --git a/res/xml/default_workspace.xml b/res/xml/default_workspace.xml
index 30c542a..0519a48 100644
--- a/res/xml/default_workspace.xml
+++ b/res/xml/default_workspace.xml
@@ -33,15 +33,6 @@
launcher:x="0"
launcher:y="0" />
- <appwidget
- launcher:packageName="com.android.protips"
- launcher:className="com.android.protips.ProtipWidget"
- launcher:screen="2"
- launcher:x="0"
- launcher:y="1"
- launcher:spanX="4"
- launcher:spanY="1" />
-
<!-- Right screen [3] -->
<appwidget
launcher:packageName="com.android.music"
@@ -52,15 +43,6 @@
launcher:spanX="4"
launcher:spanY="1" />
- <appwidget
- launcher:packageName="com.android.vending"
- launcher:className="com.android.vending.MarketWidgetProvider"
- launcher:screen="3"
- launcher:x="1"
- launcher:y="1"
- launcher:spanX="2"
- launcher:spanY="2" />
-
<!-- Far-right screen [4] -->
</favorites>
diff --git a/res/xml/wallpaper_picker_preview.xml b/res/xml/wallpaper_picker_preview.xml
new file mode 100644
index 0000000..d52e0e0
--- /dev/null
+++ b/res/xml/wallpaper_picker_preview.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<wallpaper-preview
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:staticWallpaperPreview="@drawable/wallpaper_picker_preview">
+</wallpaper-preview>
\ No newline at end of file
diff --git a/src/com/android/launcher2/Alarm.java b/src/com/android/launcher2/Alarm.java
new file mode 100644
index 0000000..38ff367
--- /dev/null
+++ b/src/com/android/launcher2/Alarm.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.os.Handler;
+
+public class Alarm implements Runnable{
+ // if we reach this time and the alarm hasn't been cancelled, call the listener
+ private long mAlarmTriggerTime;
+
+ // if we've scheduled a call to run() (ie called mHandler.postDelayed), this variable is true.
+ // We use this to avoid having multiple pending callbacks
+ private boolean mWaitingForCallback;
+
+ private Handler mHandler;
+ private OnAlarmListener mAlarmListener;
+
+ public Alarm() {
+ mHandler = new Handler();
+ }
+
+ public void setOnAlarmListener(OnAlarmListener alarmListener) {
+ mAlarmListener = alarmListener;
+ }
+
+ // Sets the alarm to go off in a certain number of milliseconds. If the alarm is already set,
+ // it's overwritten and only the new alarm setting is used
+ public void setAlarm(long millisecondsInFuture) {
+ long currentTime = System.currentTimeMillis();
+ mAlarmTriggerTime = currentTime + millisecondsInFuture;
+ if (!mWaitingForCallback) {
+ mHandler.postDelayed(this, mAlarmTriggerTime - currentTime);
+ mWaitingForCallback = true;
+ }
+ }
+
+ public void cancelAlarm() {
+ mAlarmTriggerTime = 0;
+ }
+
+ // this is called when our timer runs out
+ public void run() {
+ mWaitingForCallback = false;
+ if (mAlarmTriggerTime != 0) {
+ long currentTime = System.currentTimeMillis();
+ if (mAlarmTriggerTime > currentTime) {
+ // We still need to wait some time to trigger spring loaded mode--
+ // post a new callback
+ mHandler.postDelayed(this, Math.max(0, mAlarmTriggerTime - currentTime));
+ mWaitingForCallback = true;
+ } else {
+ if (mAlarmListener != null) {
+ mAlarmListener.onAlarm(this);
+ }
+ }
+ }
+ }
+}
+
+interface OnAlarmListener {
+ public void onAlarm(Alarm alarm);
+}
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 7ad5e49..66d9395 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -16,32 +16,30 @@
package com.android.launcher2;
+import com.android.launcher.R;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.Bitmap;
-import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.ViewGroup;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
-import android.view.ViewConfiguration;
import android.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.TextView;
import android.widget.ArrayAdapter;
import android.widget.GridView;
+import android.widget.ImageButton;
import android.widget.RelativeLayout;
+import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
-import com.android.launcher.R;
-
public class AllApps2D
extends RelativeLayout
implements AllAppsView,
@@ -58,8 +56,16 @@
private GridView mGrid;
+ /** All applications in the system (we might only be showing a subset) */
private ArrayList<ApplicationInfo> mAllAppsList = new ArrayList<ApplicationInfo>();
+ /** Currently visible applications in the grid */
+ private ArrayList<ApplicationInfo> mVisibleAppsList = new ArrayList<ApplicationInfo>();
+
+ public enum AppType { APP, GAME, DOWNLOADED, ALL };
+
+ private AppType mCurrentFilter = AppType.ALL;
+
// preserve compatibility with 3D all apps:
// 0.0 -> hidden
// 1.0 -> shown and opaque
@@ -120,30 +126,27 @@
setVisibility(View.GONE);
setSoundEffectsEnabled(false);
- mAppsAdapter = new AppsAdapter(getContext(), mAllAppsList);
- mAppsAdapter.setNotifyOnChange(false);
+ mAppsAdapter = new AppsAdapter(getContext(), mVisibleAppsList);
}
@Override
protected void onFinishInflate() {
- setBackgroundColor(Color.BLACK);
-
try {
mGrid = (GridView)findViewWithTag("all_apps_2d_grid");
if (mGrid == null) throw new Resources.NotFoundException();
mGrid.setOnItemClickListener(this);
mGrid.setOnItemLongClickListener(this);
- mGrid.setBackgroundColor(Color.BLACK);
- mGrid.setCacheColorHint(Color.BLACK);
+ // The home button is optional; some layouts might not use it
ImageButton homeButton = (ImageButton) findViewWithTag("all_apps_2d_home");
- if (homeButton == null) throw new Resources.NotFoundException();
- homeButton.setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- mLauncher.closeAllApps(true);
- }
- });
+ if (homeButton != null) {
+ homeButton.setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ mLauncher.closeAllApps(true);
+ }
+ });
+ }
} catch (Resources.NotFoundException e) {
Log.e(TAG, "Can't find necessary layout elements for AllApps2D");
}
@@ -198,10 +201,16 @@
}
}
+ @Override
public void setDragController(DragController dragger) {
mDragController = dragger;
}
+ @Override
+ public void onDragViewVisible() {
+ }
+
+ @Override
public void onDropCompleted(View target, boolean success) {
}
@@ -250,19 +259,17 @@
return mZoom > 0.001f;
}
- @Override
- public boolean isOpaque() {
- return mZoom > 0.999f;
+ public boolean isAnimating() {
+ return (getAnimation() != null);
}
public void setApps(ArrayList<ApplicationInfo> list) {
mAllAppsList.clear();
addApps(list);
+ filterApps(mCurrentFilter);
}
public void addApps(ArrayList<ApplicationInfo> list) {
-// Log.d(TAG, "addApps: " + list.size() + " apps: " + list.toString());
-
final int N = list.size();
for (int i=0; i<N; i++) {
@@ -274,11 +281,12 @@
}
mAllAppsList.add(index, item);
}
- mAppsAdapter.notifyDataSetChanged();
+ filterApps(mCurrentFilter);
}
public void removeApps(ArrayList<ApplicationInfo> list) {
final int N = list.size();
+
for (int i=0; i<N; i++) {
final ApplicationInfo item = list.get(i);
int index = findAppByComponent(mAllAppsList, item);
@@ -289,7 +297,7 @@
// Try to recover. This should keep us from crashing for now.
}
}
- mAppsAdapter.notifyDataSetChanged();
+ filterApps(mCurrentFilter);
}
public void updateApps(ArrayList<ApplicationInfo> list) {
@@ -298,6 +306,33 @@
addApps(list);
}
+ public void filterApps(AppType appType) {
+ mCurrentFilter = appType;
+
+ mAppsAdapter.setNotifyOnChange(false);
+ mVisibleAppsList.clear();
+ if (appType == AppType.ALL) {
+ mVisibleAppsList.addAll(mAllAppsList);
+ } else {
+ int searchFlags = 0;
+
+ if (appType == AppType.APP) {
+ searchFlags = ApplicationInfo.APP_FLAG;
+ } else if (appType == AppType.GAME) {
+ searchFlags = ApplicationInfo.GAME_FLAG;
+ } else if (appType == AppType.DOWNLOADED) {
+ searchFlags = ApplicationInfo.DOWNLOADED_FLAG;
+ }
+
+ for (ApplicationInfo info : mAllAppsList) {
+ if ((info.flags & searchFlags) != 0) {
+ mVisibleAppsList.add(info);
+ }
+ }
+ }
+ mAppsAdapter.notifyDataSetChanged();
+ }
+
private static int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) {
ComponentName component = item.intent.getComponent();
final int N = list.size();
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index 308ad28..2ecf761 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -16,6 +16,12 @@
package com.android.launcher2;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+import com.android.launcher.R;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
@@ -23,19 +29,7 @@
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-import android.renderscript.RenderScript;
-import android.renderscript.Sampler;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.SimpleMesh;
-import android.renderscript.Type;
+import android.renderscript.*;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -48,12 +42,6 @@
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-
-import com.android.launcher.R;
-
public class AllApps3D extends RSSurfaceView
implements AllAppsView, View.OnClickListener, View.OnLongClickListener, DragSource {
private static final String TAG = "Launcher.AllApps3D";
@@ -131,27 +119,16 @@
private boolean mSurrendered;
private int mRestoreFocusIndex = -1;
-
+
@SuppressWarnings({"UnusedDeclaration"})
static class Defines {
- public static final int ALLOC_PARAMS = 0;
- public static final int ALLOC_STATE = 1;
- public static final int ALLOC_ICON_IDS = 3;
- public static final int ALLOC_LABEL_IDS = 4;
- public static final int ALLOC_VP_CONSTANTS = 5;
-
public static final int COLUMNS_PER_PAGE_PORTRAIT = 4;
public static final int ROWS_PER_PAGE_PORTRAIT = 4;
public static final int COLUMNS_PER_PAGE_LANDSCAPE = 6;
public static final int ROWS_PER_PAGE_LANDSCAPE = 3;
- public static final int ICON_WIDTH_PX = 64;
- public static final int ICON_TEXTURE_WIDTH_PX = 74;
public static final int SELECTION_TEXTURE_WIDTH_PX = 74 + 20;
-
- public static final int ICON_HEIGHT_PX = 64;
- public static final int ICON_TEXTURE_HEIGHT_PX = 74;
public static final int SELECTION_TEXTURE_HEIGHT_PX = 74 + 20;
}
@@ -159,7 +136,6 @@
super(context, attrs);
setFocusable(true);
setSoundEffectsEnabled(false);
- getHolder().setFormat(PixelFormat.TRANSLUCENT);
final ViewConfiguration config = ViewConfiguration.get(context);
mSlop = config.getScaledTouchSlop();
mMaxFlingVelocity = config.getScaledMaximumFlingVelocity();
@@ -170,9 +146,13 @@
getHolder().setFormat(PixelFormat.TRANSLUCENT);
if (sRS == null) {
- sRS = createRenderScript(true);
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ sc.setDepth(16, 16);
+ sc.setAlpha(8, 8);
+ sRS = createRenderScriptGL(sc);
} else {
- createRenderScript(sRS);
+ // Is this even possible?
+ setRenderScriptGL(sRS);
}
final DisplayMetrics metrics = getResources().getDisplayMetrics();
@@ -196,8 +176,8 @@
public void surrender() {
if (sRS != null) {
- sRS.contextSetSurface(0, 0, null);
- sRS.mMessageCallback = null;
+ sRS.setSurface(null, 0, 0);
+ sRS.setMessageHandler(null);
}
mSurrendered = true;
}
@@ -207,12 +187,13 @@
*/
@Override
protected void onDetachedFromWindow() {
- sRS.mMessageCallback = null;
+ sRS.setMessageHandler(null);
if (!mSurrendered) {
Log.i(TAG, "onDetachedFromWindow");
- destroyRenderScript();
+ destroyRenderScriptGL();
sRS = null;
sRollo = null;
+ super.onDetachedFromWindow();
}
}
@@ -236,7 +217,7 @@
super.surfaceDestroyed(holder);
// Without this, we leak mMessageCallback which leaks the context.
if (!mSurrendered) {
- sRS.mMessageCallback = null;
+ sRS.setMessageHandler(null);
}
// We may lose any callbacks that are pending, so make sure that we re-sync that
// on the next surfaceChanged.
@@ -274,24 +255,10 @@
sRollo.dirtyCheck();
sRollo.resize(w, h);
+ Log.d(TAG, "sc " + sRS);
if (sRS != null) {
- sRS.mMessageCallback = mMessageProc = new AAMessage();
- }
-
- if (sRollo.mUniformAlloc != null) {
- float tf[] = new float[] {72.f, 72.f,
- 120.f, 120.f, 0.f, 0.f,
- 120.f, 680.f,
- (2.f / 480.f), 0, -((float)w / 2) - 0.25f, -380.25f};
- if (w > h) {
- tf[6] = 40.f;
- tf[7] = h - 40.f;
- tf[9] = 1.f;
- tf[10] = -((float)w / 2) - 0.25f;
- tf[11] = -((float)h / 2) - 0.25f;
- }
-
- sRollo.mUniformAlloc.data(tf);
+ mMessageProc = new AAMessage();
+ sRS.setMessageHandler(mMessageProc);
}
//long endTime = SystemClock.uptimeMillis();
@@ -307,18 +274,17 @@
if (mArrowNavigation) {
if (!hasWindowFocus) {
// Clear selection when we lose window focus
- mLastSelectedIcon = sRollo.mState.selectedIconIndex;
+ mLastSelectedIcon = sRollo.mScript.get_gSelectedIconIndex();
sRollo.setHomeSelected(SELECTED_NONE);
sRollo.clearSelectedIcon();
- sRollo.mState.save();
} else {
- if (sRollo.mState.iconCount > 0) {
+ if (sRollo.mScript.get_gIconCount() > 0) {
if (mLastSelection == SELECTION_ICONS) {
int selection = mLastSelectedIcon;
final int firstIcon = Math.round(sRollo.mScrollPos) * mColumnsPerPage;
if (selection < 0 || // No selection
selection < firstIcon || // off the top of the screen
- selection >= sRollo.mState.iconCount || // past last icon
+ selection >= sRollo.mScript.get_gIconCount() || // past last icon
selection >= firstIcon + // past last icon on screen
(mColumnsPerPage * mRowsPerPage)) {
selection = firstIcon;
@@ -326,10 +292,8 @@
// Select the first icon when we gain window focus
sRollo.selectIcon(selection, SELECTED_FOCUSED);
- sRollo.mState.save();
} else if (mLastSelection == SELECTION_HOME) {
sRollo.setHomeSelected(SELECTED_FOCUSED);
- sRollo.mState.save();
}
}
}
@@ -356,7 +320,6 @@
// Clear selection when we lose focus
sRollo.clearSelectedIcon();
sRollo.setHomeSelected(SELECTED_NONE);
- sRollo.mState.save();
mArrowNavigation = false;
}
} else {
@@ -366,11 +329,10 @@
}
private void gainFocus() {
- if (!mArrowNavigation && sRollo.mState.iconCount > 0) {
+ if (!mArrowNavigation && sRollo.mScript.get_gIconCount() > 0) {
// Select the first icon when we gain keyboard focus
mArrowNavigation = true;
sRollo.selectIcon(Math.round(sRollo.mScrollPos) * mColumnsPerPage, SELECTED_FOCUSED);
- sRollo.mState.save();
}
}
@@ -382,7 +344,7 @@
if (!isVisible()) {
return false;
}
- final int iconCount = sRollo.mState.iconCount;
+ final int iconCount = sRollo.mScript.get_gIconCount();
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) {
if (mArrowNavigation) {
@@ -390,7 +352,7 @@
reallyPlaySoundEffect(SoundEffectConstants.CLICK);
mLauncher.closeAllApps(true);
} else {
- int whichApp = sRollo.mState.selectedIconIndex;
+ int whichApp = sRollo.mScript.get_gSelectedIconIndex();
if (whichApp >= 0) {
ApplicationInfo app = mAllAppsList.get(whichApp);
mLauncher.startActivitySafely(app.intent, app);
@@ -402,10 +364,10 @@
if (iconCount > 0) {
final boolean isPortrait = getWidth() < getHeight();
-
+
mArrowNavigation = true;
- int currentSelection = sRollo.mState.selectedIconIndex;
+ int currentSelection = sRollo.mScript.get_gSelectedIconIndex();
int currentTopRow = Math.round(sRollo.mScrollPos);
// The column of the current selection, in the range 0..COLUMNS_PER_PAGE_PORTRAIT-1
@@ -511,7 +473,6 @@
}
if (newSelection != currentSelection) {
sRollo.selectIcon(newSelection, SELECTED_FOCUSED);
- sRollo.mState.save();
}
}
return handled;
@@ -611,7 +572,6 @@
(!isPortrait && x > mTouchXBorders[mTouchXBorders.length-1])) {
mTouchTracking = TRACKING_HOME;
sRollo.setHomeSelected(SELECTED_PRESSED);
- sRollo.mState.save();
mCurrentIconIndex = -1;
} else {
mTouchTracking = TRACKING_FLING;
@@ -619,9 +579,6 @@
mMotionDownRawX = (int)ev.getRawX();
mMotionDownRawY = (int)ev.getRawY();
- sRollo.mState.newPositionX = ev.getRawY() / getHeight();
- sRollo.mState.newTouchDown = 1;
-
if (!sRollo.checkClickOK()) {
sRollo.clearSelectedIcon();
} else {
@@ -632,8 +589,7 @@
cancelLongPress();
}
}
- sRollo.mState.save();
- sRollo.move();
+ sRollo.move(ev.getRawY() / getHeight());
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(ev);
mStartedScrolling = false;
@@ -646,7 +602,6 @@
y > mTouchYBorders[mTouchYBorders.length-1]) || (!isPortrait
&& x > mTouchXBorders[mTouchXBorders.length-1])
? SELECTED_PRESSED : SELECTED_NONE);
- sRollo.mState.save();
} else if (mTouchTracking == TRACKING_FLING) {
int rawY = (int)ev.getRawY();
int slop;
@@ -667,14 +622,11 @@
cancelLongPress();
mCurrentIconIndex = -1;
}
- sRollo.mState.newPositionX = ev.getRawY() / getHeight();
- sRollo.mState.newTouchDown = 1;
- sRollo.move();
+ sRollo.move(ev.getRawY() / getHeight());
mStartedScrolling = true;
sRollo.clearSelectedIcon();
mVelocityTracker.addMovement(ev);
- sRollo.mState.save();
}
}
break;
@@ -688,18 +640,13 @@
mLauncher.closeAllApps(true);
}
sRollo.setHomeSelected(SELECTED_NONE);
- sRollo.mState.save();
}
mCurrentIconIndex = -1;
} else if (mTouchTracking == TRACKING_FLING) {
- sRollo.mState.newTouchDown = 0;
- sRollo.mState.newPositionX = ev.getRawY() / getHeight();
-
mVelocityTracker.computeCurrentVelocity(1000 /* px/sec */, mMaxFlingVelocity);
- sRollo.mState.flingVelocity = mVelocityTracker.getYVelocity() / getHeight();
sRollo.clearSelectedIcon();
- sRollo.mState.save();
- sRollo.fling();
+ sRollo.fling(ev.getRawY() / getHeight(),
+ mVelocityTracker.getYVelocity() / getHeight());
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
@@ -766,7 +713,7 @@
int pos = -1;
switch (mLastSelection) {
case SELECTION_ICONS:
- index = sRollo.mState.selectedIconIndex;
+ index = sRollo.mScript.get_gSelectedIconIndex();
if (index >= 0) {
ApplicationInfo info = mAllAppsList.get(index);
if (info.title != null) {
@@ -791,10 +738,16 @@
return false;
}
+ @Override
public void setDragController(DragController dragger) {
mDragController = dragger;
}
+ @Override
+ public void onDragViewVisible() {
+ }
+
+ @Override
public void onDropCompleted(View target, boolean success) {
}
@@ -825,8 +778,8 @@
return sRollo != null && mZoom > 0.001f;
}
- public boolean isOpaque() {
- return mZoom > 0.999f;
+ public boolean isAnimating() {
+ return isVisible() && mZoom <= 0.999f;
}
public void setApps(ArrayList<ApplicationInfo> list) {
@@ -858,13 +811,12 @@
if (sRollo != null && reload) {
sRollo.setApps(list);
}
-
+
if (hasFocus() && mRestoreFocusIndex != -1) {
sRollo.selectIcon(mRestoreFocusIndex, SELECTED_FOCUSED);
- sRollo.mState.save();
mRestoreFocusIndex = -1;
}
-
+
mLocks &= ~LOCK_ICONS_PENDING;
}
@@ -881,7 +833,7 @@
final int N = list.size();
if (sRollo != null) {
sRollo.pause();
- sRollo.reallocAppsList(sRollo.mState.iconCount + N);
+ sRollo.reallocAppsList(sRollo.mScript.get_gIconCount() + N);
}
for (int i=0; i<N; i++) {
@@ -951,18 +903,7 @@
return -1;
}
- /*
- private static int countPages(int iconCount) {
- int iconsPerPage = getColumnsCount() * Defines.ROWS_PER_PAGE_PORTRAIT;
- int pages = iconCount / iconsPerPage;
- if (pages*iconsPerPage != iconCount) {
- pages++;
- }
- return pages;
- }
- */
-
- class AAMessage extends RenderScript.RSMessage {
+ class AAMessage extends RenderScript.RSMessageHandler {
public void run() {
sRollo.mScrollPos = ((float)mData[0]) / (1 << 16);
mVelocity = ((float)mData[1]) / (1 << 16);
@@ -993,57 +934,31 @@
private int mHeight;
private Resources mRes;
- private Script mScript;
- private Script.Invokable mInvokeMove;
- private Script.Invokable mInvokeMoveTo;
- private Script.Invokable mInvokeFling;
- private Script.Invokable mInvokeResetWAR;
- private Script.Invokable mInvokeSetZoom;
+ ScriptC_allapps mScript;
- private ProgramStore mPSIcons;
- private ProgramFragment mPFTexMip;
- private ProgramFragment mPFTexMipAlpha;
- private ProgramFragment mPFTexNearest;
- private ProgramVertex mPV;
- private ProgramVertex mPVCurve;
- private SimpleMesh mMesh;
- private ProgramVertex.MatrixAllocation mPVA;
+ private Mesh mMesh;
+ private ProgramVertexFixedFunction.Constants mPVA;
- private Allocation mUniformAlloc;
+ private ScriptField_VpConsts mUniformAlloc;
private Allocation mHomeButtonNormal;
private Allocation mHomeButtonFocused;
private Allocation mHomeButtonPressed;
private Allocation[] mIcons;
- private int[] mIconIds;
- private Allocation mAllocIconIds;
+ private Allocation mAllocIcons;
private Allocation[] mLabels;
- private int[] mLabelIds;
- private Allocation mAllocLabelIds;
- private Allocation mSelectedIcon;
+ private Allocation mAllocLabels;
private Bitmap mSelectionBitmap;
private Canvas mSelectionCanvas;
-
- private float mScrollPos;
- Params mParams;
- State mState;
+ private float mScrollPos;
AllApps3D mAllApps;
boolean mInitialize;
- class BaseAlloc {
- Allocation mAlloc;
- Type mType;
-
- void save() {
- mAlloc.data(this);
- }
- }
-
private boolean checkClickOK() {
return (Math.abs(mAllApps.mVelocity) < 0.4f) &&
(Math.abs(mScrollPos - Math.round(mScrollPos)) < 0.4f);
@@ -1051,48 +966,13 @@
void pause() {
if (sRS != null) {
- sRS.contextBindRootScript(null);
+ sRS.bindRootScript(null);
}
}
void resume() {
if (sRS != null) {
- sRS.contextBindRootScript(mScript);
- }
- }
-
- class Params extends BaseAlloc {
- Params() {
- mType = Type.createFromClass(sRS, Params.class, 1, "ParamsClass");
- mAlloc = Allocation.createTyped(sRS, mType);
- save();
- }
- public int bubbleWidth;
- public int bubbleHeight;
- public int bubbleBitmapWidth;
- public int bubbleBitmapHeight;
-
- public int homeButtonWidth;
- public int homeButtonHeight;
- public int homeButtonTextureWidth;
- public int homeButtonTextureHeight;
- }
-
- class State extends BaseAlloc {
- public float newPositionX;
- public int newTouchDown;
- public float flingVelocity;
- public int iconCount;
- public int selectedIconIndex = -1;
- public int selectedIconTexture;
- public float zoomTarget;
- public int homeButtonId;
- public float targetPos;
-
- State() {
- mType = Type.createFromClass(sRS, State.class, 1, "StateClass");
- mAlloc = Allocation.createTyped(sRS, mType);
- save();
+ sRS.bindRootScript(mScript);
}
}
@@ -1104,16 +984,21 @@
mRes = res;
mWidth = width;
mHeight = height;
+ mScript = new ScriptC_allapps(sRS, mRes, R.raw.allapps);
+
initProgramVertex();
initProgramFragment();
initProgramStore();
initGl();
initData();
- initRs();
+
+ mScript.bind_gIcons(mAllocIcons);
+ mScript.bind_gLabels(mAllocLabels);
+ sRS.bindRootScript(mScript);
}
public void initMesh() {
- SimpleMesh.TriangleMeshBuilder tm = new SimpleMesh.TriangleMeshBuilder(sRS, 2, 0);
+ Mesh.TriangleMeshBuilder tm = new Mesh.TriangleMeshBuilder(sRS, 2, 0);
for (int ct=0; ct < 16; ct++) {
float pos = (1.f / (16.f - 1)) * ct;
@@ -1124,38 +1009,77 @@
tm.addTriangle(ct, ct+1, ct+2);
tm.addTriangle(ct+1, ct+3, ct+2);
}
- mMesh = tm.create();
- mMesh.setName("SMCell");
+ mMesh = tm.create(true);
+ mScript.set_gSMCell(mMesh);
+ }
+
+ Matrix4f getProjectionMatrix(int w, int h) {
+ // range -1,1 in the narrow axis at z = 0.
+ Matrix4f m1 = new Matrix4f();
+ Matrix4f m2 = new Matrix4f();
+
+ if(w > h) {
+ float aspect = ((float)w) / h;
+ m1.loadFrustum(-aspect,aspect, -1,1, 1,100);
+ } else {
+ float aspect = ((float)h) / w;
+ m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
+ }
+
+ m2.loadRotate(180, 0, 1, 0);
+ m1.loadMultiply(m1, m2);
+
+ m2.loadScale(-2, 2, 1);
+ m1.loadMultiply(m1, m2);
+
+ m2.loadTranslate(0, 0, 2);
+ m1.loadMultiply(m1, m2);
+ return m1;
}
void resize(int w, int h) {
- mPVA.setupProjectionNormalized(w, h);
+ Matrix4f proj = getProjectionMatrix(w, h);
+ mPVA.setProjection(proj);
+
+ if (mUniformAlloc != null) {
+ ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
+ i.Proj = proj;
+ 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;
+ }
+ mUniformAlloc.set(i, 0, true);
+ }
+
mWidth = w;
mHeight = h;
}
private void initProgramVertex() {
- mPVA = new ProgramVertex.MatrixAllocation(sRS);
+ mPVA = new ProgramVertexFixedFunction.Constants(sRS);
resize(mWidth, mHeight);
- ProgramVertex.Builder pvb = new ProgramVertex.Builder(sRS, null, null);
+ ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(sRS);
pvb.setTextureMatrixEnable(true);
- mPV = pvb.create();
- mPV.setName("PV");
- mPV.bindAllocation(mPVA);
+ ProgramVertex pv = pvb.create();
+ ((ProgramVertexFixedFunction)pv).bindConstants(mPVA);
+ sRS.bindProgramVertex(pv);
- Element.Builder eb = new Element.Builder(sRS);
- eb.add(Element.createVector(sRS, Element.DataType.FLOAT_32, 2), "ImgSize");
- eb.add(Element.createVector(sRS, Element.DataType.FLOAT_32, 4), "Position");
- eb.add(Element.createVector(sRS, Element.DataType.FLOAT_32, 2), "BendPos");
- eb.add(Element.createVector(sRS, Element.DataType.FLOAT_32, 4), "ScaleOffset");
- Element e = eb.create();
-
- mUniformAlloc = Allocation.createSized(sRS, e, 1);
+ mUniformAlloc = new ScriptField_VpConsts(sRS, 1);
+ mScript.bind_vpConstants(mUniformAlloc);
initMesh();
- ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(sRS);
- String t = "void main() {\n" +
+ ProgramVertex.Builder sb = new ProgramVertex.Builder(sRS);
+ String t = "varying vec4 varColor;\n" +
+ "varying vec2 varTex0;\n" +
+ "void main() {\n" +
// Animation
" float ani = UNI_Position.z;\n" +
@@ -1205,97 +1129,81 @@
" pos.z -= ani * 1.5;\n" +
" lum *= 1.0 - ani;\n" +
- " gl_Position = UNI_MVP * pos;\n" +
+ " gl_Position = UNI_Proj * pos;\n" +
" varColor.rgba = vec4(lum, lum, lum, 1.0);\n" +
" varTex0.xy = ATTRIB_position;\n" +
" varTex0.y = 1.0 - varTex0.y;\n" +
- " varTex0.zw = vec2(0.0, 0.0);\n" +
"}\n";
sb.setShader(t);
sb.addConstant(mUniformAlloc.getType());
- sb.addInput(mMesh.getVertexType(0).getElement());
- mPVCurve = sb.create();
- mPVCurve.setName("PVCurve");
- mPVCurve.bindAllocation(mPVA);
- mPVCurve.bindConstants(mUniformAlloc, 1);
+ sb.addInput(mMesh.getVertexAllocation(0).getType().getElement());
+ ProgramVertex pvc = sb.create();
+ pvc.bindConstants(mUniformAlloc.getAllocation(), 0);
- sRS.contextBindProgramVertex(mPV);
+ mScript.set_gPVCurve(pvc);
}
private void initProgramFragment() {
Sampler.Builder sb = new Sampler.Builder(sRS);
- sb.setMin(Sampler.Value.LINEAR_MIP_LINEAR);
- sb.setMag(Sampler.Value.NEAREST);
+ sb.setMinification(Sampler.Value.LINEAR_MIP_LINEAR);
+ sb.setMagnification(Sampler.Value.NEAREST);
sb.setWrapS(Sampler.Value.CLAMP);
sb.setWrapT(Sampler.Value.CLAMP);
Sampler linear = sb.create();
- sb.setMin(Sampler.Value.NEAREST);
- sb.setMag(Sampler.Value.NEAREST);
+ sb.setMinification(Sampler.Value.NEAREST);
+ sb.setMagnification(Sampler.Value.NEAREST);
Sampler nearest = sb.create();
- ProgramFragment.Builder bf = new ProgramFragment.Builder(sRS);
- bf.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
- ProgramFragment.Builder.Format.RGBA, 0);
- mPFTexMip = bf.create();
- mPFTexMip.setName("PFTexMip");
- mPFTexMip.bindSampler(linear, 0);
+ ProgramFragmentFixedFunction.Builder bf = new ProgramFragmentFixedFunction.Builder(sRS);
+ bf.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
+ ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+ bf.setVaryingColor(true);
+ ProgramFragment pfTexMip = bf.create();
+ pfTexMip.bindSampler(linear, 0);
- mPFTexNearest = bf.create();
- mPFTexNearest.setName("PFTexNearest");
- mPFTexNearest.bindSampler(nearest, 0);
+ bf.setVaryingColor(false);
+ ProgramFragment pfTexNearest = bf.create();
+ pfTexNearest.bindSampler(nearest, 0);
- bf.setTexture(ProgramFragment.Builder.EnvMode.MODULATE,
- ProgramFragment.Builder.Format.ALPHA, 0);
- mPFTexMipAlpha = bf.create();
- mPFTexMipAlpha.setName("PFTexMipAlpha");
- mPFTexMipAlpha.bindSampler(linear, 0);
+ bf.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
+ ProgramFragmentFixedFunction.Builder.Format.ALPHA, 0);
+ bf.setVaryingColor(true);
+ ProgramFragment pfTexMipAlpha = bf.create();
+ pfTexMipAlpha.bindSampler(linear, 0);
+ mScript.set_gPFTexNearest(pfTexNearest);
+ mScript.set_gPFTexMip(pfTexMip);
+ mScript.set_gPFTexMipAlpha(pfTexMipAlpha);
}
private void initProgramStore() {
- ProgramStore.Builder bs = new ProgramStore.Builder(sRS, null, null);
+ ProgramStore.Builder bs = new ProgramStore.Builder(sRS);
bs.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
- bs.setColorMask(true,true,true,false);
- bs.setDitherEnable(true);
+ bs.setColorMaskEnabled(true,true,true,false);
+ bs.setDitherEnabled(true);
bs.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
- mPSIcons = bs.create();
- mPSIcons.setName("PSIcons");
+ mScript.set_gPS(bs.create());
}
private void initGl() {
}
private void initData() {
- mParams = new Params();
- mState = new State();
-
- final Utilities.BubbleText bubble = new Utilities.BubbleText(mAllApps.getContext());
-
- mParams.bubbleWidth = bubble.getBubbleWidth();
- mParams.bubbleHeight = bubble.getMaxBubbleHeight();
- mParams.bubbleBitmapWidth = bubble.getBitmapWidth();
- mParams.bubbleBitmapHeight = bubble.getBitmapHeight();
+ mScript.set_COLUMNS_PER_PAGE_PORTRAIT(Defines.COLUMNS_PER_PAGE_PORTRAIT);
+ mScript.set_ROWS_PER_PAGE_PORTRAIT(Defines.ROWS_PER_PAGE_PORTRAIT);
+ mScript.set_COLUMNS_PER_PAGE_LANDSCAPE(Defines.COLUMNS_PER_PAGE_LANDSCAPE);
+ mScript.set_ROWS_PER_PAGE_LANDSCAPE(Defines.ROWS_PER_PAGE_LANDSCAPE);
mHomeButtonNormal = Allocation.createFromBitmapResource(sRS, mRes,
- R.drawable.home_button_normal, Element.RGBA_8888(sRS), false);
- mHomeButtonNormal.uploadToTexture(0);
+ R.drawable.home_button_normal);
mHomeButtonFocused = Allocation.createFromBitmapResource(sRS, mRes,
- R.drawable.home_button_focused, Element.RGBA_8888(sRS), false);
- mHomeButtonFocused.uploadToTexture(0);
+ R.drawable.home_button_focused);
mHomeButtonPressed = Allocation.createFromBitmapResource(sRS, mRes,
- R.drawable.home_button_pressed, Element.RGBA_8888(sRS), false);
- mHomeButtonPressed.uploadToTexture(0);
- mParams.homeButtonWidth = 76;
- mParams.homeButtonHeight = 68;
- mParams.homeButtonTextureWidth = 128;
- mParams.homeButtonTextureHeight = 128;
+ R.drawable.home_button_pressed);
- mState.homeButtonId = mHomeButtonNormal.getID();
-
- mParams.save();
- mState.save();
+ mScript.set_gHomeButton(mHomeButtonNormal);
mSelectionBitmap = Bitmap.createBitmap(Defines.SELECTION_TEXTURE_WIDTH_PX,
Defines.SELECTION_TEXTURE_HEIGHT_PX, Bitmap.Config.ARGB_8888);
@@ -1304,30 +1212,6 @@
setApps(null);
}
- private void initRs() {
- ScriptC.Builder sb = new ScriptC.Builder(sRS);
- sb.setScript(mRes, R.raw.allapps);
- sb.setRoot(true);
- sb.addDefines(mAllApps.mDefines);
- sb.setType(mParams.mType, "params", Defines.ALLOC_PARAMS);
- sb.setType(mState.mType, "state", Defines.ALLOC_STATE);
- sb.setType(mUniformAlloc.getType(), "vpConstants", Defines.ALLOC_VP_CONSTANTS);
- mInvokeMove = sb.addInvokable("move");
- mInvokeFling = sb.addInvokable("fling");
- mInvokeMoveTo = sb.addInvokable("moveTo");
- mInvokeResetWAR = sb.addInvokable("resetHWWar");
- mInvokeSetZoom = sb.addInvokable("setZoom");
- mScript = sb.create();
- mScript.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- mScript.bindAllocation(mParams.mAlloc, Defines.ALLOC_PARAMS);
- mScript.bindAllocation(mState.mAlloc, Defines.ALLOC_STATE);
- mScript.bindAllocation(mAllocIconIds, Defines.ALLOC_ICON_IDS);
- mScript.bindAllocation(mAllocLabelIds, Defines.ALLOC_LABEL_IDS);
- mScript.bindAllocation(mUniformAlloc, Defines.ALLOC_VP_CONSTANTS);
-
- sRS.contextBindRootScript(mScript);
- }
-
void dirtyCheck() {
if (sZoomDirty) {
setZoom(mAllApps.sNextZoom, mAllApps.sAnimateNextZoom);
@@ -1344,21 +1228,17 @@
}
mIcons = new Allocation[count];
- mIconIds = new int[allocCount];
- mAllocIconIds = Allocation.createSized(sRS, Element.USER_I32(sRS), allocCount);
+ mAllocIcons = Allocation.createSized(sRS, Element.ALLOCATION(sRS), allocCount);
mLabels = new Allocation[count];
- mLabelIds = new int[allocCount];
- mAllocLabelIds = Allocation.createSized(sRS, Element.USER_I32(sRS), allocCount);
+ mAllocLabels = Allocation.createSized(sRS, Element.ALLOCATION(sRS), allocCount);
- mState.iconCount = count;
- for (int i=0; i < mState.iconCount; i++) {
+ mScript.set_gIconCount(count);
+ for (int i=0; i < count; i++) {
createAppIconAllocations(i, list.get(i));
}
- for (int i=0; i < mState.iconCount; i++) {
- uploadAppIcon(i, list.get(i));
- }
saveAppsList();
+ android.util.Log.e("rs", "setApps");
sRollo.resume();
}
@@ -1367,35 +1247,16 @@
sRollo.clearSelectedIcon();
sRollo.setHomeSelected(SELECTED_NONE);
}
- if (zoom > 0.001f) {
- sRollo.mState.zoomTarget = zoom;
- } else {
- sRollo.mState.zoomTarget = 0;
- }
- sRollo.mState.save();
- if (!animate) {
- sRollo.mInvokeSetZoom.execute();
- }
+ sRollo.mScript.invoke_setZoom(zoom, animate ? 1 : 0);
}
private void createAppIconAllocations(int index, ApplicationInfo item) {
mIcons[index] = Allocation.createFromBitmap(sRS, item.iconBitmap,
- Element.RGBA_8888(sRS), false);
+ Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
mLabels[index] = Allocation.createFromBitmap(sRS, item.titleBitmap,
- Element.A_8(sRS), false);
- mIconIds[index] = mIcons[index].getID();
- mLabelIds[index] = mLabels[index].getID();
- }
-
- private void uploadAppIcon(int index, ApplicationInfo item) {
- if (mIconIds[index] != mIcons[index].getID()) {
- throw new IllegalStateException("uploadAppIcon index=" + index
- + " mIcons[index].getID=" + mIcons[index].getID()
- + " mIconsIds[index]=" + mIconIds[index]
- + " item=" + item);
- }
- mIcons[index].uploadToTexture(true, 0);
- mLabels[index].uploadToTexture(true, 0);
+ Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
}
/**
@@ -1404,62 +1265,50 @@
*/
private void reallocAppsList(int count) {
Allocation[] icons = new Allocation[count];
- int[] iconIds = new int[count];
- mAllocIconIds = Allocation.createSized(sRS, Element.USER_I32(sRS), count);
+ mAllocIcons = Allocation.createSized(sRS, Element.ALLOCATION(sRS), count);
Allocation[] labels = new Allocation[count];
- int[] labelIds = new int[count];
- mAllocLabelIds = Allocation.createSized(sRS, Element.USER_I32(sRS), count);
+ mAllocLabels = Allocation.createSized(sRS, Element.ALLOCATION(sRS), count);
- final int oldCount = sRollo.mState.iconCount;
+ final int oldCount = sRollo.mScript.get_gIconCount();
System.arraycopy(mIcons, 0, icons, 0, oldCount);
- System.arraycopy(mIconIds, 0, iconIds, 0, oldCount);
System.arraycopy(mLabels, 0, labels, 0, oldCount);
- System.arraycopy(mLabelIds, 0, labelIds, 0, oldCount);
mIcons = icons;
- mIconIds = iconIds;
mLabels = labels;
- mLabelIds = labelIds;
}
/**
* Handle the allocations for the new app. Make sure you call saveAppsList when done.
*/
private void addApp(int index, ApplicationInfo item) {
- final int count = mState.iconCount - index;
+ final int count = mScript.get_gIconCount() - index;
final int dest = index + 1;
System.arraycopy(mIcons, index, mIcons, dest, count);
- System.arraycopy(mIconIds, index, mIconIds, dest, count);
System.arraycopy(mLabels, index, mLabels, dest, count);
- System.arraycopy(mLabelIds, index, mLabelIds, dest, count);
createAppIconAllocations(index, item);
- uploadAppIcon(index, item);
- sRollo.mState.iconCount++;
+
+ mScript.set_gIconCount(mScript.get_gIconCount() + 1);
}
/**
* Handle the allocations for the removed app. Make sure you call saveAppsList when done.
*/
private void removeApp(int index) {
- final int count = mState.iconCount - index - 1;
+ final int count = mScript.get_gIconCount() - index - 1;
final int src = index + 1;
System.arraycopy(mIcons, src, mIcons, index, count);
- System.arraycopy(mIconIds, src, mIconIds, index, count);
System.arraycopy(mLabels, src, mLabels, index, count);
- System.arraycopy(mLabelIds, src, mLabelIds, index, count);
- sRollo.mState.iconCount--;
- final int last = mState.iconCount;
+ mScript.set_gIconCount(mScript.get_gIconCount() - 1);
+ final int last = mScript.get_gIconCount();
mIcons[last] = null;
- mIconIds[last] = 0;
mLabels[last] = null;
- mLabelIds[last] = 0;
}
/**
@@ -1467,35 +1316,27 @@
*/
private void saveAppsList() {
// WTF: how could mScript be not null but mAllocIconIds null b/2460740.
- if (mScript != null && mAllocIconIds != null) {
- mAllocIconIds.data(mIconIds);
- mAllocLabelIds.data(mLabelIds);
-
- mScript.bindAllocation(mAllocIconIds, Defines.ALLOC_ICON_IDS);
- mScript.bindAllocation(mAllocLabelIds, Defines.ALLOC_LABEL_IDS);
-
- mState.save();
-
- // Note: mScript may be null if we haven't initialized it yet.
- // In that case, this is a no-op.
- if (mInvokeResetWAR != null) {
- mInvokeResetWAR.execute();
+ if (mScript != null && mAllocIcons != null) {
+ if (mIcons.length > 0) {
+ mAllocIcons.copyFrom(mIcons);
+ mAllocLabels.copyFrom(mLabels);
}
+
+ mScript.bind_gIcons(mAllocIcons);
+ mScript.bind_gLabels(mAllocLabels);
}
}
- void fling() {
- mInvokeFling.execute();
+ void fling(float pos, float v) {
+ mScript.invoke_fling(pos, v);
}
- void move() {
- mInvokeMove.execute();
+ void move(float pos) {
+ mScript.invoke_move(pos);
}
void moveTo(float row) {
- mState.targetPos = row;
- mState.save();
- mInvokeMoveTo.execute();
+ mScript.invoke_moveTo(row);
}
/**
@@ -1525,7 +1366,7 @@
if (mAllApps != null) {
mAllApps.mRestoreFocusIndex = index;
}
- mState.selectedIconIndex = -1;
+ mScript.set_gSelectedIconIndex(-1);
if (mAllApps.mLastSelection == SELECTION_ICONS) {
mAllApps.mLastSelection = SELECTION_NONE;
}
@@ -1534,8 +1375,8 @@
mAllApps.mLastSelection = SELECTION_ICONS;
}
- int prev = mState.selectedIconIndex;
- mState.selectedIconIndex = index;
+ int prev = mScript.get_gSelectedIconIndex();
+ mScript.set_gSelectedIconIndex(index);
ApplicationInfo info = appsList.get(index);
Bitmap selectionBitmap = mSelectionBitmap;
@@ -1544,10 +1385,8 @@
selectionBitmap.getWidth(), selectionBitmap.getHeight(),
pressed == SELECTED_PRESSED, info.iconBitmap);
- mSelectedIcon = Allocation.createFromBitmap(sRS, selectionBitmap,
- Element.RGBA_8888(sRS), false);
- mSelectedIcon.uploadToTexture(0);
- mState.selectedIconTexture = mSelectedIcon.getID();
+ Allocation si = Allocation.createFromBitmap(sRS, selectionBitmap);
+ mScript.set_gSelectedIconTexture(si);
if (prev != index) {
if (info.title != null && info.title.length() > 0) {
@@ -1562,24 +1401,24 @@
* You need to call save() on mState on your own after calling this.
*/
void clearSelectedIcon() {
- mState.selectedIconIndex = -1;
+ mScript.set_gSelectedIconIndex(-1);
}
void setHomeSelected(int mode) {
final int prev = mAllApps.mLastSelection;
switch (mode) {
case SELECTED_NONE:
- mState.homeButtonId = mHomeButtonNormal.getID();
+ mScript.set_gHomeButton(mHomeButtonNormal);
break;
case SELECTED_FOCUSED:
mAllApps.mLastSelection = SELECTION_HOME;
- mState.homeButtonId = mHomeButtonFocused.getID();
+ mScript.set_gHomeButton(mHomeButtonFocused);
if (prev != SELECTION_HOME) {
mAllApps.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
break;
case SELECTED_PRESSED:
- mState.homeButtonId = mHomeButtonPressed.getID();
+ mScript.set_gHomeButton(mHomeButtonPressed);
break;
}
}
@@ -1591,31 +1430,15 @@
if (mIcons != null) {
Log.d(TAG, "sRollo.mIcons.length=" + mIcons.length);
}
- if (mIconIds != null) {
- Log.d(TAG, "sRollo.mIconIds.length=" + mIconIds.length);
- }
- Log.d(TAG, "sRollo.mIconIds=" + Arrays.toString(mIconIds));
- if (mLabelIds != null) {
- Log.d(TAG, "sRollo.mLabelIds.length=" + mLabelIds.length);
- }
- Log.d(TAG, "sRollo.mLabelIds=" + Arrays.toString(mLabelIds));
- Log.d(TAG, "sRollo.mState.newPositionX=" + mState.newPositionX);
- Log.d(TAG, "sRollo.mState.newTouchDown=" + mState.newTouchDown);
- Log.d(TAG, "sRollo.mState.flingVelocity=" + mState.flingVelocity);
- Log.d(TAG, "sRollo.mState.iconCount=" + mState.iconCount);
- Log.d(TAG, "sRollo.mState.selectedIconIndex=" + mState.selectedIconIndex);
- Log.d(TAG, "sRollo.mState.selectedIconTexture=" + mState.selectedIconTexture);
- Log.d(TAG, "sRollo.mState.zoomTarget=" + mState.zoomTarget);
- Log.d(TAG, "sRollo.mState.homeButtonId=" + mState.homeButtonId);
- Log.d(TAG, "sRollo.mState.targetPos=" + mState.targetPos);
- Log.d(TAG, "sRollo.mParams.bubbleWidth=" + mParams.bubbleWidth);
- Log.d(TAG, "sRollo.mParams.bubbleHeight=" + mParams.bubbleHeight);
- Log.d(TAG, "sRollo.mParams.bubbleBitmapWidth=" + mParams.bubbleBitmapWidth);
- Log.d(TAG, "sRollo.mParams.bubbleBitmapHeight=" + mParams.bubbleBitmapHeight);
- Log.d(TAG, "sRollo.mParams.homeButtonWidth=" + mParams.homeButtonWidth);
- Log.d(TAG, "sRollo.mParams.homeButtonHeight=" + mParams.homeButtonHeight);
- Log.d(TAG, "sRollo.mParams.homeButtonTextureWidth=" + mParams.homeButtonTextureWidth);
- Log.d(TAG, "sRollo.mParams.homeButtonTextureHeight=" + mParams.homeButtonTextureHeight);
+ //Log.d(TAG, "sRollo.mState.newPositionX=" + mState.newPositionX);
+ //Log.d(TAG, "sRollo.mState.newTouchDown=" + mState.newTouchDown);
+ //Log.d(TAG, "sRollo.mState.flingVelocity=" + mState.flingVelocity);
+ //Log.d(TAG, "sRollo.mState.iconCount=" + mState.iconCount);
+ //Log.d(TAG, "sRollo.mState.selectedIconIndex=" + mState.selectedIconIndex);
+ //Log.d(TAG, "sRollo.mState.selectedIconTexture=" + mState.selectedIconTexture);
+ //Log.d(TAG, "sRollo.mState.zoomTarget=" + mState.zoomTarget);
+ //Log.d(TAG, "sRollo.mState.homeButtonId=" + mState.homeButtonId);
+ //Log.d(TAG, "sRollo.mState.targetPos=" + mState.targetPos);
}
}
@@ -1642,9 +1465,7 @@
sRollo.dumpState();
}
if (sRS != null) {
- sRS.contextDump(0);
+ sRS.contextDump();
}
}
}
-
-
diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java
index 3a5baea..4c9bc5e 100644
--- a/src/com/android/launcher2/AllAppsList.java
+++ b/src/com/android/launcher2/AllAppsList.java
@@ -16,17 +16,16 @@
package com.android.launcher2;
+import java.util.ArrayList;
+import java.util.List;
+
import android.content.ComponentName;
-import android.content.Intent;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
* Stores the list of all applications for the all apps view.
@@ -92,7 +91,7 @@
if (matches.size() > 0) {
for (ResolveInfo info : matches) {
- add(new ApplicationInfo(info, mIconCache));
+ add(new ApplicationInfo(context.getPackageManager(), info, mIconCache));
}
}
}
@@ -143,7 +142,7 @@
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
if (applicationInfo == null) {
- add(new ApplicationInfo(info, mIconCache));
+ add(new ApplicationInfo(context.getPackageManager(), info, mIconCache));
} else {
mIconCache.remove(applicationInfo.componentName);
mIconCache.getTitleAndIcon(applicationInfo, info);
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
new file mode 100644
index 0000000..5906599
--- /dev/null
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.widget.Checkable;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+
+/**
+ * An implementation of PagedView that populates the pages of the workspace
+ * with all of the user's applications.
+ */
+public class AllAppsPagedView extends PagedViewWithDraggableItems implements AllAppsView,
+ View.OnClickListener, DragSource, DropTarget {
+
+ private static final String TAG = "AllAppsPagedView";
+
+ private Launcher mLauncher;
+ private DragController mDragController;
+
+ // preserve compatibility with 3D all apps:
+ // 0.0 -> hidden
+ // 1.0 -> shown and opaque
+ // intermediate values -> partially shown & partially opaque
+ private float mZoom;
+
+ // set of all applications
+ private ArrayList<ApplicationInfo> mApps;
+ private ArrayList<ApplicationInfo> mFilteredApps;
+
+ // the types of applications to filter
+ static final int ALL_APPS_FLAG = -1;
+ private int mAppFilter = ALL_APPS_FLAG;
+
+ private final LayoutInflater mInflater;
+
+
+ public AllAppsPagedView(Context context) {
+ this(context, null);
+ }
+
+ public AllAppsPagedView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AllAppsPagedView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedView, defStyle, 0);
+ mCellCountX = a.getInt(R.styleable.PagedView_cellCountX, 6);
+ mCellCountY = a.getInt(R.styleable.PagedView_cellCountY, 4);
+ mInflater = LayoutInflater.from(context);
+ a.recycle();
+ setSoundEffectsEnabled(false);
+
+ Resources r = context.getResources();
+ setDragSlopeThreshold(
+ r.getInteger(R.integer.config_allAppsDrawerDragSlopeThreshold) / 100.0f);
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+ mCenterPagesVertically = false;
+ }
+
+ @Override
+ public void setLauncher(Launcher launcher) {
+ mLauncher = launcher;
+ mLauncher.setAllAppsPagedView(this);
+ }
+
+ @Override
+ public void setDragController(DragController dragger) {
+ mDragController = dragger;
+ }
+
+ public void setAppFilter(int filterType) {
+ mAppFilter = filterType;
+ if (mApps != null) {
+ mFilteredApps = rebuildFilteredApps(mApps);
+ setCurrentPage(0);
+ invalidatePageData();
+ }
+ }
+
+ @Override
+ public void zoom(float zoom, boolean animate) {
+ mZoom = zoom;
+ cancelLongPress();
+
+ if (isVisible()) {
+ getParent().bringChildToFront(this);
+ setVisibility(View.VISIBLE);
+ if (animate) {
+ startAnimation(AnimationUtils.loadAnimation(getContext(),
+ R.anim.all_apps_2d_fade_in));
+ } else {
+ onAnimationEnd();
+ }
+ } else {
+ if (animate) {
+ startAnimation(AnimationUtils.loadAnimation(getContext(),
+ R.anim.all_apps_2d_fade_out));
+ } else {
+ onAnimationEnd();
+ }
+ }
+ }
+
+ protected void onAnimationEnd() {
+ if (!isVisible()) {
+ setVisibility(View.GONE);
+ mZoom = 0.0f;
+
+ endChoiceMode();
+ } else {
+ mZoom = 1.0f;
+ }
+
+ if (mLauncher != null)
+ mLauncher.zoomed(mZoom);
+ }
+
+ private int getChildIndexForGrandChild(View v) {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+ if (layout.indexOfChild(v) > -1) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public void onClick(View v) {
+ // if we are already in a choice mode, then just change the selection
+ if (v instanceof Checkable) {
+ if (!isChoiceMode(CHOICE_MODE_NONE)) {
+ Checkable c = (Checkable) v;
+ if (isChoiceMode(CHOICE_MODE_SINGLE)) {
+ // Uncheck all the other grandchildren, and toggle the clicked one
+ boolean wasChecked = c.isChecked();
+ resetCheckedGrandchildren();
+ c.setChecked(!wasChecked);
+ } else {
+ c.toggle();
+ }
+ if (getCheckedGrandchildren().size() == 0) {
+ endChoiceMode();
+ }
+
+ return;
+ }
+ }
+
+ // otherwise continue and launch the application
+ int childIndex = getChildIndexForGrandChild(v);
+ if (childIndex == getCurrentPage()) {
+ final ApplicationInfo app = (ApplicationInfo) v.getTag();
+
+ // animate some feedback to the click
+ animateClickFeedback(v, new Runnable() {
+ @Override
+ public void run() {
+ mLauncher.startActivitySafely(app.intent, app);
+ }
+ });
+
+ endChoiceMode();
+ }
+ }
+
+ private void setupDragMode() {
+ mLauncher.getWorkspace().shrink(Workspace.ShrinkState.BOTTOM_VISIBLE);
+ DeleteZone allAppsDeleteZone = (DeleteZone)
+ mLauncher.findViewById(R.id.all_apps_delete_zone);
+ allAppsDeleteZone.setDragAndDropEnabled(true);
+
+ ApplicationInfoDropTarget allAppsInfoButton =
+ (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target);
+ allAppsInfoButton.setDragAndDropEnabled(true);
+ }
+
+ private void tearDownDragMode() {
+ 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() {
+ DeleteZone allAppsDeleteZone =
+ (DeleteZone) mLauncher.findViewById(R.id.all_apps_delete_zone);
+ // if onDestroy was called on Launcher, we might have already deleted the
+ // all apps delete zone / info button, so check if they are null
+ if (allAppsDeleteZone != null) allAppsDeleteZone.setDragAndDropEnabled(false);
+
+ ApplicationInfoDropTarget allAppsInfoButton =
+ (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target);
+ if (allAppsInfoButton != null) allAppsInfoButton.setDragAndDropEnabled(false);
+ }
+ });
+ resetCheckedGrandchildren();
+ mDragController.removeDropTarget(this);
+ }
+
+ @Override
+ protected boolean beginDragging(View v) {
+ if (!v.isInTouchMode()) return false;
+ if (!super.beginDragging(v)) return false;
+
+ // Start drag mode after the item is selected
+ setupDragMode();
+
+ ApplicationInfo app = (ApplicationInfo) v.getTag();
+ app = new ApplicationInfo(app);
+
+ // get icon (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);
+
+ // 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) {
+ // In preparation for drag, we always reset the checked grand children regardless of
+ // what choice mode we are in
+ resetCheckedGrandchildren();
+
+ // Toggle the selection on the dragged app
+ Checkable checkable = (Checkable) v;
+
+ // Note: we toggle the checkable state to actually cause an alpha fade for the duration
+ // of the drag of the item. (The fade-in will occur when all checked states are
+ // disabled when dragging ends)
+ checkable.toggle();
+ }
+
+ // Start the drag
+ mLauncher.lockScreenOrientation();
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
+ mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, null);
+ b.recycle();
+ return true;
+ }
+
+ @Override
+ public void onDragViewVisible() {
+ }
+
+ @Override
+ public void onDropCompleted(View target, boolean success) {
+ // close the choice action mode if we have a proper drop
+ if (target != this) {
+ endChoiceMode();
+ }
+ tearDownDragMode();
+ mLauncher.getWorkspace().onDragStopped(success);
+ mLauncher.unlockScreenOrientation();
+ }
+
+ @Override
+ public boolean isVisible() {
+ return mZoom > 0.001f;
+ }
+
+ @Override
+ public boolean isAnimating() {
+ return (getAnimation() != null);
+ }
+
+ private ArrayList<ApplicationInfo> rebuildFilteredApps(ArrayList<ApplicationInfo> apps) {
+ ArrayList<ApplicationInfo> filteredApps = new ArrayList<ApplicationInfo>();
+ if (mAppFilter == ALL_APPS_FLAG) {
+ return apps;
+ } else {
+ final int length = apps.size();
+ for (int i = 0; i < length; ++i) {
+ ApplicationInfo info = apps.get(i);
+ if ((info.flags & mAppFilter) > 0) {
+ filteredApps.add(info);
+ }
+ }
+ Collections.sort(filteredApps, LauncherModel.APP_INSTALL_TIME_COMPARATOR);
+ }
+ return filteredApps;
+ }
+
+ @Override
+ public void setApps(ArrayList<ApplicationInfo> list) {
+ mApps = list;
+ Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR);
+ mFilteredApps = rebuildFilteredApps(mApps);
+ mPageViewIconCache.retainAllApps(list);
+ invalidatePageData();
+ }
+
+ private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+ // we add it in place, in alphabetical order
+ final int count = list.size();
+ for (int i = 0; i < count; ++i) {
+ final ApplicationInfo info = list.get(i);
+ final int index = Collections.binarySearch(mApps, info, LauncherModel.APP_NAME_COMPARATOR);
+ if (index < 0) {
+ mApps.add(-(index + 1), info);
+ } else {
+ mApps.add(index, info);
+ }
+ }
+ mFilteredApps = rebuildFilteredApps(mApps);
+ }
+ @Override
+ public void addApps(ArrayList<ApplicationInfo> list) {
+ addAppsWithoutInvalidate(list);
+ invalidatePageData();
+ }
+
+ private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+ // End the choice mode if any of the items in the list that are being removed are
+ // currently selected
+ ArrayList<Checkable> checkedList = getCheckedGrandchildren();
+ HashSet<ApplicationInfo> checkedAppInfos = new HashSet<ApplicationInfo>();
+ for (Checkable checked : checkedList) {
+ PagedViewIcon icon = (PagedViewIcon) checked;
+ checkedAppInfos.add((ApplicationInfo) icon.getTag());
+ }
+ for (ApplicationInfo info : list) {
+ if (checkedAppInfos.contains(info)) {
+ endChoiceMode();
+ break;
+ }
+ }
+
+ // Loop through all the apps and remove apps that have the same component
+ final int length = list.size();
+ for (int i = 0; i < length; ++i) {
+ final ApplicationInfo info = list.get(i);
+ int removeIndex = findAppByComponent(mApps, info);
+ if (removeIndex > -1) {
+ mApps.remove(removeIndex);
+ mPageViewIconCache.removeOutline(new PagedViewIconCache.Key(info));
+ }
+ }
+ mFilteredApps = rebuildFilteredApps(mApps);
+ }
+ @Override
+ public void removeApps(ArrayList<ApplicationInfo> list) {
+ removeAppsWithoutInvalidate(list);
+ invalidatePageData();
+ }
+
+ @Override
+ public void updateApps(ArrayList<ApplicationInfo> list) {
+ removeAppsWithoutInvalidate(list);
+ addAppsWithoutInvalidate(list);
+ invalidatePageData();
+ }
+
+ private int findAppByComponent(ArrayList<ApplicationInfo> list, ApplicationInfo item) {
+ ComponentName removeComponent = item.intent.getComponent();
+ final 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;
+ }
+
+ @Override
+ public void dumpState() {
+ ApplicationInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
+ }
+
+ @Override
+ public void surrender() {
+ // do nothing?
+ }
+
+ @Override
+ public void syncPages() {
+ // ensure that we have the right number of pages (min of 1, since we have placeholders)
+ int numPages = Math.max(1,
+ (int) Math.ceil((float) mFilteredApps.size() / (mCellCountX * mCellCountY)));
+ int curNumPages = getChildCount();
+ // remove any extra pages after the "last" page
+ int extraPageDiff = curNumPages - numPages;
+ for (int i = 0; i < extraPageDiff; ++i) {
+ removeViewAt(numPages);
+ }
+ // add any necessary pages
+ for (int i = curNumPages; i < numPages; ++i) {
+ PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
+ layout.setCellCount(mCellCountX, mCellCountY);
+ layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
+ mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
+ layout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap);
+ addView(layout);
+ }
+
+ // bound the current page
+ setCurrentPage(Math.max(0, Math.min(numPages - 1, getCurrentPage())));
+ }
+
+ @Override
+ public void syncPageItems(int page) {
+ // Ensure that we have the right number of items on the pages
+ final int cellsPerPage = mCellCountX * mCellCountY;
+ final int startIndex = page * cellsPerPage;
+ final int endIndex = Math.min(startIndex + cellsPerPage, mFilteredApps.size());
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
+
+ if (!mFilteredApps.isEmpty()) {
+ int curNumPageItems = layout.getChildCount();
+ int numPageItems = endIndex - startIndex;
+
+ // If we were previously an empty page, then restart anew
+ boolean wasEmptyPage = false;
+ if (curNumPageItems == 1) {
+ View icon = layout.getChildAt(0);
+ if (icon.getTag() == null) {
+ wasEmptyPage = true;
+ }
+ }
+
+ if (wasEmptyPage) {
+ // Remove all the previous items
+ curNumPageItems = 0;
+ layout.removeAllViews();
+ } else {
+ // Remove any extra items
+ int extraPageItemsDiff = curNumPageItems - numPageItems;
+ for (int i = 0; i < extraPageItemsDiff; ++i) {
+ layout.removeViewAt(numPageItems);
+ }
+ }
+
+ // Add any necessary items
+ for (int i = curNumPageItems; i < numPageItems; ++i) {
+ TextView text = (TextView) mInflater.inflate(
+ R.layout.all_apps_paged_view_application, layout, false);
+ text.setOnClickListener(this);
+ text.setOnLongClickListener(this);
+ text.setOnTouchListener(this);
+
+ layout.addViewToCellLayout(text, -1, i,
+ new PagedViewCellLayout.LayoutParams(0, 0, 1, 1));
+ }
+
+ // 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);
+ PagedViewIcon icon = (PagedViewIcon) layout.getChildAt(index);
+ icon.applyFromApplicationInfo(info, mPageViewIconCache, true, (numPages > 1));
+
+ PagedViewCellLayout.LayoutParams params =
+ (PagedViewCellLayout.LayoutParams) icon.getLayoutParams();
+ params.cellX = index % mCellCountX;
+ params.cellY = index / mCellCountX;
+ }
+
+ // Default to left-aligned icons
+ layout.enableCenteredContent(false);
+ } else {
+ // There are no items, so show the user a small message
+ TextView icon = (TextView) mInflater.inflate(
+ R.layout.all_apps_no_items_placeholder, layout, false);
+ switch (mAppFilter) {
+ case ApplicationInfo.DOWNLOADED_FLAG:
+ icon.setText(mContext.getString(R.string.all_apps_no_downloads));
+ break;
+ default: break;
+ }
+
+ // Center-align the message
+ layout.enableCenteredContent(true);
+ layout.removeAllViews();
+ layout.addViewToCellLayout(icon, -1, 0,
+ new PagedViewCellLayout.LayoutParams(0, 0, 4, 1));
+ }
+ }
+
+ /*
+ * We don't actually use AllAppsPagedView as a drop target... it's only used to intercept a drop
+ * to the workspace.
+ */
+ @Override
+ public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ return false;
+ }
+ @Override
+ public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset,
+ int yOffset, DragView dragView, Object dragInfo) {
+ return null;
+ }
+ @Override
+ public void onDragEnter(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) {}
+ @Override
+ public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {}
+ @Override
+ public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {}
+
+ public boolean isDropEnabled() {
+ return true;
+ }
+}
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
new file mode 100644
index 0000000..47a5bf7
--- /dev/null
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * Implements a tabbed version of AllApps2D.
+ */
+public class AllAppsTabbed extends TabHost implements AllAppsView {
+
+ private static final String TAG = "Launcher.AllAppsTabbed";
+
+ private static final String TAG_ALL = "ALL";
+ private static final String TAG_DOWNLOADED = "DOWNLOADED";
+
+ private AllAppsPagedView mAllApps;
+ private Context mContext;
+ private final LayoutInflater mInflater;
+ private boolean mFirstLayout = true;
+
+ public AllAppsTabbed(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ mInflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ // setup the tab host
+ setup();
+
+ try {
+ mAllApps = (AllAppsPagedView) findViewById(R.id.all_apps_paged_view);
+ if (mAllApps == null) throw new Resources.NotFoundException();
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "Can't find necessary layout elements for AllAppsTabbed");
+ }
+
+ // share the same AllApps workspace across all the tabs
+ TabContentFactory contentFactory = new TabContentFactory() {
+ public View createTabContent(String tag) {
+ return mAllApps;
+ }
+ };
+
+ TextView tabView;
+ TabWidget tabWidget = (TabWidget) findViewById(com.android.internal.R.id.tabs);
+ tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
+ tabView.setText(mContext.getString(R.string.all_apps_tab_all));
+ addTab(newTabSpec(TAG_ALL).setIndicator(tabView).setContent(contentFactory));
+
+ tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
+ tabView.setText(mContext.getString(R.string.all_apps_tab_downloaded));
+ addTab(newTabSpec(TAG_DOWNLOADED).setIndicator(tabView).setContent(contentFactory));
+
+ 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 float alpha = mAllApps.getAlpha();
+ ValueAnimator alphaAnim = ObjectAnimator.ofFloat(mAllApps, "alpha", alpha, 0.0f).
+ setDuration(duration);
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ String tag = getCurrentTabTag();
+ if (tag == TAG_ALL) {
+ mAllApps.setAppFilter(AllAppsPagedView.ALL_APPS_FLAG);
+ } else if (tag == TAG_DOWNLOADED) {
+ mAllApps.setAppFilter(ApplicationInfo.DOWNLOADED_FLAG);
+ }
+
+ final float alpha = mAllApps.getAlpha();
+ ObjectAnimator.ofFloat(mAllApps, "alpha", alpha, 1.0f).
+ setDuration(duration).start();
+ }
+ });
+ alphaAnim.start();
+ }
+ });
+
+ // It needs to be INVISIBLE so that it will be measured in the layout.
+ // Otherwise the animations is messed up when we show it for the first time.
+ setVisibility(INVISIBLE);
+ }
+
+ @Override
+ public void setLauncher(Launcher launcher) {
+ mAllApps.setLauncher(launcher);
+ }
+
+ @Override
+ public void setDragController(DragController dragger) {
+ mAllApps.setDragController(dragger);
+ }
+
+ @Override
+ public void zoom(float zoom, boolean animate) {
+ // NOTE: animate parameter is ignored for the TabHost itself
+ setVisibility((zoom == 0.0f) ? View.GONE : View.VISIBLE);
+ mAllApps.zoom(zoom, animate);
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ if (visibility == View.GONE && mFirstLayout) {
+ // It needs to be INVISIBLE so that it will be measured in the layout.
+ // Otherwise the animations is messed up when we show it for the first time.
+ visibility = View.INVISIBLE;
+ }
+ final boolean isVisible = (visibility == View.VISIBLE);
+ super.setVisibility(visibility);
+ float zoom = (isVisible ? 1.0f : 0.0f);
+ mAllApps.zoom(zoom, false);
+ }
+
+ @Override
+ public boolean isVisible() {
+ return mAllApps.isVisible();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ mFirstLayout = false;
+ super.onLayout(changed, l, t, r, b);
+ }
+
+ @Override
+ public boolean isAnimating() {
+ return (getAnimation() != null);
+ }
+
+ @Override
+ public void setApps(ArrayList<ApplicationInfo> list) {
+ mAllApps.setApps(list);
+ }
+
+ @Override
+ public void addApps(ArrayList<ApplicationInfo> list) {
+ mAllApps.addApps(list);
+ }
+
+ @Override
+ public void removeApps(ArrayList<ApplicationInfo> list) {
+ mAllApps.removeApps(list);
+ }
+
+ @Override
+ public void updateApps(ArrayList<ApplicationInfo> list) {
+ mAllApps.updateApps(list);
+ }
+
+ @Override
+ public void dumpState() {
+ mAllApps.dumpState();
+ }
+
+ @Override
+ public void surrender() {
+ mAllApps.surrender();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (ev.getY() > mAllApps.getBottom()) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
index 877c075..007ecf8 100644
--- a/src/com/android/launcher2/AllAppsView.java
+++ b/src/com/android/launcher2/AllAppsView.java
@@ -31,7 +31,7 @@
public boolean isVisible();
- public boolean isOpaque();
+ public boolean isAnimating();
public void setApps(ArrayList<ApplicationInfo> list);
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
index 5bb5037..3adea37 100644
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ b/src/com/android/launcher2/ApplicationInfo.java
@@ -17,12 +17,11 @@
package com.android.launcher2;
import android.content.ComponentName;
-import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
import android.util.Log;
import java.util.ArrayList;
@@ -31,6 +30,7 @@
* Represents an app in AllAppsView.
*/
class ApplicationInfo extends ItemInfo {
+ private static final String TAG = "Launcher2.ApplicationInfo";
/**
* The application name.
@@ -52,8 +52,17 @@
*/
Bitmap iconBitmap;
+ /**
+ * The time at which the app was first installed.
+ */
+ long firstInstallTime;
+
ComponentName componentName;
+ static final int APP_FLAG = 1;
+ static final int GAME_FLAG = 2;
+ static final int DOWNLOADED_FLAG = 4;
+ int flags = 0;
ApplicationInfo() {
itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
@@ -62,15 +71,33 @@
/**
* Must not hold the Context.
*/
- public ApplicationInfo(ResolveInfo info, IconCache iconCache) {
- this.componentName = new ComponentName(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
+ public ApplicationInfo(PackageManager pm, ResolveInfo info, IconCache iconCache) {
+ final String packageName = info.activityInfo.applicationInfo.packageName;
+ this.componentName = new ComponentName(packageName, info.activityInfo.name);
this.container = ItemInfo.NO_ID;
this.setActivity(componentName,
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ try {
+ int appFlags = pm.getApplicationInfo(packageName, 0).flags;
+ if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
+ flags |= DOWNLOADED_FLAG;
+ }
+ if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+ flags |= DOWNLOADED_FLAG;
+ }
+ firstInstallTime = pm.getPackageInfo(packageName, 0).firstInstallTime;
+ // TODO: Figure out how to determine what is a game
+
+ // If it's not a game, it's an app
+ if ((flags & GAME_FLAG) == 0) {
+ flags |= APP_FLAG;
+ }
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);
+ }
+
iconCache.getTitleAndIcon(this, info);
}
@@ -79,6 +106,8 @@
componentName = info.componentName;
title = info.title.toString();
intent = new Intent(info.intent);
+ flags = info.flags;
+ firstInstallTime = info.firstInstallTime;
}
/**
@@ -106,7 +135,8 @@
Log.d(tag, label + " size=" + list.size());
for (ApplicationInfo info: list) {
Log.d(tag, " title=\"" + info.title + "\" titleBitmap=" + info.titleBitmap
- + " iconBitmap=" + info.iconBitmap);
+ + " iconBitmap=" + info.iconBitmap + " firstInstallTime="
+ + info.firstInstallTime);
}
}
diff --git a/src/com/android/launcher2/ApplicationInfoDropTarget.java b/src/com/android/launcher2/ApplicationInfoDropTarget.java
new file mode 100644
index 0000000..78a9d2d
--- /dev/null
+++ b/src/com/android/launcher2/ApplicationInfoDropTarget.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.Animator.AnimatorListener;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Implements a DropTarget which allows applications to be dropped on it,
+ * in order to launch the application info for that app.
+ */
+public class ApplicationInfoDropTarget extends IconDropTarget {
+ private static final int sFadeInAnimationDuration = 200;
+ private static final int sFadeOutAnimationDuration = 100;
+
+ private AnimatorSet mFadeAnimator;
+
+ public ApplicationInfoDropTarget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ApplicationInfoDropTarget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // Set the hover paint colour
+ int colour = getContext().getResources().getColor(R.color.app_info_filter);
+ mHoverPaint.setColorFilter(new PorterDuffColorFilter(colour, PorterDuff.Mode.SRC_ATOP));
+
+ if (LauncherApplication.isScreenXLarge()) {
+ // 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(
+ R.dimen.delete_zone_vertical_drag_padding);
+ int lr = getResources().getDimensionPixelSize(
+ R.dimen.delete_zone_horizontal_drag_padding);
+ setDragPadding(tb, lr, tb, 0);
+ }
+ }
+
+ public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ // acceptDrop is called just before onDrop. We do the work here, rather than
+ // in onDrop, because it allows us to reject the drop (by returning false)
+ // so that the object being dragged isn't removed from the home screen.
+ if (getVisibility() != VISIBLE) return false;
+
+ ComponentName componentName = null;
+ if (dragInfo instanceof ApplicationInfo) {
+ componentName = ((ApplicationInfo)dragInfo).componentName;
+ } else if (dragInfo instanceof ShortcutInfo) {
+ componentName = ((ShortcutInfo)dragInfo).intent.getComponent();
+ }
+ mLauncher.startApplicationDetailsActivity(componentName);
+ return false;
+ }
+
+ public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ if (!mDragAndDropEnabled) return;
+ dragView.setPaint(mHoverPaint);
+ }
+
+ public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ if (!mDragAndDropEnabled) return;
+ dragView.setPaint(null);
+ }
+
+ public void onDragStart(DragSource source, Object info, int dragAction) {
+ if (info != null && mDragAndDropEnabled) {
+ final int itemType = ((ItemInfo)info).itemType;
+ mActive = (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
+ if (mActive) {
+ // Fade in this icon
+ if (mFadeAnimator != null) mFadeAnimator.cancel();
+ mFadeAnimator = new AnimatorSet();
+ Animator infoButtonAnimator = ObjectAnimator.ofFloat(this, "alpha", 0.0f, 1.0f);
+ infoButtonAnimator.setDuration(sFadeInAnimationDuration);
+
+ mFadeAnimator.play(infoButtonAnimator);
+
+ setVisibility(VISIBLE);
+
+ // Fade out the overlapping views
+ if (mOverlappingViews != null) {
+ for (View view : mOverlappingViews) {
+ ObjectAnimator oa = ObjectAnimator.ofFloat(view, "alpha", 0.0f);
+ oa.setDuration(sFadeOutAnimationDuration);
+ mFadeAnimator.play(oa);
+ }
+ mFadeAnimator.addListener(new AnimatorListener() {
+ public void onAnimationStart(Animator animation) {}
+ public void onAnimationRepeat(Animator animation) {}
+ public void onAnimationEnd(Animator animation) {
+ onEndOrCancel();
+ }
+ public void onAnimationCancel(Animator animation) {
+ onEndOrCancel();
+ }
+ private void onEndOrCancel() {
+ for (View view : mOverlappingViews) {
+ view.setVisibility(INVISIBLE);
+ }
+ mFadeAnimator = null;
+ }
+ });
+ }
+ mFadeAnimator.start();
+ }
+ }
+ }
+
+ public void onDragEnd() {
+ if (!mDragAndDropEnabled) return;
+ if (mActive) mActive = false;
+
+ // Fade out this icon
+ if (mFadeAnimator != null) mFadeAnimator.cancel();
+ mFadeAnimator = new AnimatorSet();
+ Animator infoButtonAnimator = ObjectAnimator.ofFloat(this, "alpha", 0.0f);
+ infoButtonAnimator.setDuration(sFadeOutAnimationDuration);
+ mFadeAnimator.addListener(new AnimatorListener() {
+ public void onAnimationStart(Animator animation) {}
+ public void onAnimationRepeat(Animator animation) {}
+ public void onAnimationEnd(Animator animation) {
+ onEndOrCancel();
+ }
+ public void onAnimationCancel(Animator animation) {
+ onEndOrCancel();
+ }
+ private void onEndOrCancel() {
+ setVisibility(GONE);
+ mFadeAnimator = null;
+ }
+ });
+ mFadeAnimator.play(infoButtonAnimator);
+
+ // 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);
+ }
+ }
+ mFadeAnimator.start();
+ }
+}
diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java
index 4a56e1b..f3aa342 100644
--- a/src/com/android/launcher2/BubbleTextView.java
+++ b/src/com/android/launcher2/BubbleTextView.java
@@ -16,35 +16,56 @@
package com.android.launcher2;
-import android.widget.TextView;
-import android.content.Context;
-import android.util.AttributeSet;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.text.Layout;
-
import com.android.launcher.R;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Region.Op;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
/**
* TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan
* because we want to make the bubble taller than the text and TextView's clip is
* too aggressive.
*/
-public class BubbleTextView extends TextView {
- static final float CORNER_RADIUS = 8.0f;
- static final float PADDING_H = 5.0f;
- static final float PADDING_V = 1.0f;
+public class BubbleTextView extends CachedTextView implements VisibilityChangedBroadcaster {
+ static final float CORNER_RADIUS = 4.0f;
+ static final float SHADOW_LARGE_RADIUS = 4.0f;
+ static final float SHADOW_SMALL_RADIUS = 1.75f;
+ static final float SHADOW_Y_OFFSET = 2.0f;
+ static final int SHADOW_LARGE_COLOUR = 0xCC000000;
+ static final int SHADOW_SMALL_COLOUR = 0xBB000000;
+ static final float PADDING_H = 8.0f;
+ static final float PADDING_V = 3.0f;
- private final RectF mRect = new RectF();
private Paint mPaint;
+ private float mBubbleColorAlpha;
+ private int mPrevAlpha = -1;
+
+ private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper();
+ private final Canvas mTempCanvas = new Canvas();
+ private final Rect mTempRect = new Rect();
+ private final Paint mTempPaint = new Paint();
+ private boolean mDidInvalidateForPressedState;
+ private Bitmap mPressedOrFocusedBackground;
+ private int mFocusedOutlineColor;
+ private int mFocusedGlowColor;
+ private int mPressedOutlineColor;
+ private int mPressedGlowColor;
private boolean mBackgroundSizeChanged;
private Drawable mBackground;
- private float mCornerRadius;
- private float mPaddingH;
- private float mPaddingV;
+
+ private VisibilityChangedListener mOnVisibilityChangedListener;
public BubbleTextView(Context context) {
super(context);
@@ -62,18 +83,42 @@
}
private void init() {
- setFocusable(true);
mBackground = getBackground();
+ setFocusable(true);
setBackgroundDrawable(null);
+ final Resources res = getContext().getResources();
+ int bubbleColor = res.getColor(R.color.bubble_dark_background);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPaint.setColor(getContext().getResources().getColor(R.color.bubble_dark_background));
+ mPaint.setColor(bubbleColor);
+ mBubbleColorAlpha = Color.alpha(bubbleColor) / 255.0f;
+ mFocusedOutlineColor = res.getColor(R.color.workspace_item_focused_outline_color);
+ mFocusedGlowColor = res.getColor(R.color.workspace_item_focused_glow_color);
+ mPressedOutlineColor = res.getColor(R.color.workspace_item_pressed_outline_color);
+ mPressedGlowColor = res.getColor(R.color.workspace_item_pressed_glow_color);
+ }
- final float scale = getContext().getResources().getDisplayMetrics().density;
- mCornerRadius = CORNER_RADIUS * scale;
- mPaddingH = PADDING_H * scale;
- //noinspection PointlessArithmeticExpression
- mPaddingV = PADDING_V * scale;
+ protected int getCacheTopPadding() {
+ return (int) PADDING_V;
+ }
+ protected int getCacheBottomPadding() {
+ return (int) (PADDING_V + SHADOW_LARGE_RADIUS + SHADOW_Y_OFFSET);
+ }
+ protected int getCacheLeftPadding() {
+ return (int) (PADDING_H + SHADOW_LARGE_RADIUS);
+ }
+ protected int getCacheRightPadding() {
+ return (int) (PADDING_H + SHADOW_LARGE_RADIUS);
+ }
+
+ public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) {
+ Bitmap b = info.getIcon(iconCache);
+
+ setCompoundDrawablesWithIntrinsicBounds(null,
+ new FastBitmapDrawable(b),
+ null, null);
+ setText(info.title);
+ setTag(info);
}
@Override
@@ -91,6 +136,28 @@
@Override
protected void drawableStateChanged() {
+ if (isPressed()) {
+ // In this case, we have already created the pressed outline on ACTION_DOWN,
+ // so we just need to do an invalidate to trigger draw
+ if (!mDidInvalidateForPressedState) {
+ invalidate();
+ }
+ } else {
+ // Otherwise, either clear the pressed/focused background, or create a background
+ // for the focused state
+ final boolean backgroundEmptyBefore = mPressedOrFocusedBackground == null;
+ mPressedOrFocusedBackground = null;
+ if (isFocused()) {
+ mPressedOrFocusedBackground = createGlowingOutline(
+ mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor);
+ invalidate();
+ }
+ final boolean backgroundEmptyNow = mPressedOrFocusedBackground == null;
+ if (!backgroundEmptyBefore && backgroundEmptyNow) {
+ invalidate();
+ }
+ }
+
Drawable d = mBackground;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
@@ -98,50 +165,158 @@
super.drawableStateChanged();
}
+ /**
+ * Draw the View v into the given Canvas.
+ *
+ * @param v the view to draw
+ * @param destCanvas the canvas to draw on
+ * @param padding the horizontal and vertical padding to use when drawing
+ */
+ private void drawWithPadding(Canvas destCanvas, int padding) {
+ final Rect clipRect = mTempRect;
+ getDrawingRect(clipRect);
+
+ // adjust the clip rect so that we don't include the text label
+ clipRect.bottom =
+ getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + getLayout().getLineTop(0);
+
+ // Draw the View into the bitmap.
+ // The translate of scrollX and scrollY is necessary when drawing TextViews, because
+ // they set scrollX and scrollY to large values to achieve centered text
+ destCanvas.save();
+ destCanvas.translate(-getScrollX() + padding / 2, -getScrollY() + padding / 2);
+ destCanvas.clipRect(clipRect, Op.REPLACE);
+ draw(destCanvas);
+ destCanvas.restore();
+ }
+
+ /**
+ * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
+ * Responsibility for the bitmap is transferred to the caller.
+ */
+ private Bitmap createGlowingOutline(Canvas canvas, int outlineColor, int glowColor) {
+ final int padding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
+ final Bitmap b = Bitmap.createBitmap(
+ getWidth() + padding, getHeight() + padding, Bitmap.Config.ARGB_8888);
+
+ canvas.setBitmap(b);
+ drawWithPadding(canvas, padding);
+ mOutlineHelper.applyExtraThickExpensiveOutlineWithBlur(b, canvas, glowColor, outlineColor);
+
+ return b;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ // Call the superclass onTouchEvent first, because sometimes it changes the state to
+ // isPressed() on an ACTION_UP
+ boolean result = super.onTouchEvent(event);
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ // So that the pressed outline is visible immediately when isPressed() is true,
+ // we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time
+ // to create it)
+ if (mPressedOrFocusedBackground == null) {
+ mPressedOrFocusedBackground = createGlowingOutline(
+ mTempCanvas, mPressedGlowColor, mPressedOutlineColor);
+ }
+ // Invalidate so the pressed state is visible, or set a flag so we know that we
+ // have to call invalidate as soon as the state is "pressed"
+ if (isPressed()) {
+ mDidInvalidateForPressedState = true;
+ invalidate();
+ } else {
+ mDidInvalidateForPressedState = false;
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ // If we've touched down and up on an item, and it's still not "pressed", then
+ // destroy the pressed outline
+ if (!isPressed()) {
+ mPressedOrFocusedBackground = null;
+ }
+ break;
+ }
+ return result;
+ }
+
+ public void setVisibilityChangedListener(VisibilityChangedListener listener) {
+ mOnVisibilityChangedListener = listener;
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ if (mOnVisibilityChangedListener != null) {
+ mOnVisibilityChangedListener.receiveVisibilityChangedMessage(this);
+ }
+ super.onVisibilityChanged(changedView, visibility);
+ }
+
@Override
public void draw(Canvas canvas) {
- final Drawable background = mBackground;
- if (background != null) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
-
- if (mBackgroundSizeChanged) {
- background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
- mBackgroundSizeChanged = false;
- }
-
- if ((scrollX | scrollY) == 0) {
- background.draw(canvas);
- } else {
- canvas.translate(scrollX, scrollY);
- background.draw(canvas);
- canvas.translate(-scrollX, -scrollY);
- }
+ if (mPressedOrFocusedBackground != null && (isPressed() || isFocused())) {
+ // The blue glow can extend outside of our clip region, so we first temporarily expand
+ // the canvas's clip region
+ canvas.save(Canvas.CLIP_SAVE_FLAG);
+ int padding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS / 2;
+ canvas.clipRect(-padding + mScrollX, -padding + mScrollY,
+ getWidth() + padding + mScrollX, getHeight() + padding + mScrollY,
+ Region.Op.REPLACE);
+ // draw blue glow
+ canvas.drawBitmap(mPressedOrFocusedBackground,
+ mScrollX - padding, mScrollY - padding, mTempPaint);
+ canvas.restore();
}
+ if (isBuildingCache()) {
+ // We enhance the shadow by drawing the shadow twice
+ this.setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR);
+ super.draw(canvas);
+ this.setShadowLayer(SHADOW_SMALL_RADIUS, 0.0f, 0.0f, SHADOW_SMALL_COLOUR);
+ super.draw(canvas);
+ } else {
+ final Drawable background = mBackground;
+ if (background != null) {
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
- final Layout layout = getLayout();
- final RectF rect = mRect;
- final int left = getCompoundPaddingLeft();
- final int top = getExtendedPaddingTop();
+ if (mBackgroundSizeChanged) {
+ background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
+ mBackgroundSizeChanged = false;
+ }
- rect.set(left + layout.getLineLeft(0) - mPaddingH,
- top + layout.getLineTop(0) - mPaddingV,
- Math.min(left + layout.getLineRight(0) + mPaddingH, mScrollX + mRight - mLeft),
- top + layout.getLineBottom(0) + mPaddingV);
- canvas.drawRoundRect(rect, mCornerRadius, mCornerRadius, mPaint);
-
- super.draw(canvas);
+ if ((scrollX | scrollY) == 0) {
+ background.draw(canvas);
+ } else {
+ canvas.translate(scrollX, scrollY);
+ background.draw(canvas);
+ canvas.translate(-scrollX, -scrollY);
+ }
+ }
+ super.draw(canvas);
+ }
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- mBackground.setCallback(this);
+ if (mBackground != null) mBackground.setCallback(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mBackground.setCallback(null);
+ if (mBackground != null) mBackground.setCallback(null);
+ }
+
+ @Override
+ protected boolean onSetAlpha(int alpha) {
+ if (mPrevAlpha != alpha) {
+ mPrevAlpha = alpha;
+ mPaint.setAlpha((int) (alpha * mBubbleColorAlpha));
+ super.onSetAlpha(alpha);
+ }
+ return true;
}
}
diff --git a/src/com/android/launcher2/CachedTextView.java b/src/com/android/launcher2/CachedTextView.java
new file mode 100644
index 0000000..eaa6636
--- /dev/null
+++ b/src/com/android/launcher2/CachedTextView.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Bitmap.Config;
+import android.graphics.PorterDuff.Mode;
+import android.text.Layout;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+/*
+ * This class is a bit of a hack, designed to speed up long text labels in Launcher. It caches the
+ * text in a TextView to a bitmap and then just draws that Bitmap instead afterward, speeding up
+ * rendering. Marquee scrolling is not currently supported.
+ *
+ */
+public class CachedTextView extends TextView {
+ private Bitmap mCache;
+ private final Paint mCachePaint = new Paint();
+ private final Canvas mCacheCanvas = new Canvas();
+
+ private int mPrevAlpha = -1;
+ private boolean mIsBuildingCache;
+ boolean mIsTextCacheDirty;
+ float mTextCacheLeft;
+ float mTextCacheTop;
+ float mTextCacheScrollX;
+ float mRectLeft, mRectTop;
+ private float mPaddingH = 0;
+ private float mPaddingV = 0;
+ private CharSequence mText;
+
+ public CachedTextView(Context context) {
+ super(context);
+ }
+
+ public CachedTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CachedTextView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ protected int getCacheTopPadding() {
+ return 0;
+ }
+ protected int getCacheLeftPadding() {
+ return 0;
+ }
+ protected int getCacheRightPadding() {
+ return 0;
+ }
+ protected int getCacheBottomPadding() {
+ return 0;
+ }
+
+ public void setText(CharSequence text, BufferType type) {
+ super.setText(text, type);
+ mIsTextCacheDirty = true;
+ }
+
+ private void buildAndUpdateCache() {
+ final Layout layout = getLayout();
+ final int left = getCompoundPaddingLeft();
+ final int top = getExtendedPaddingTop();
+ final float prevAlpha = getAlpha();
+
+ mTextCacheLeft = layout.getLineLeft(0) - getCacheLeftPadding();
+ mTextCacheTop = top + layout.getLineTop(0) - mPaddingV - getCacheTopPadding();
+
+ mRectLeft = mScrollX + getLeft();
+ mRectTop = 0;
+ mTextCacheScrollX = mScrollX;
+
+ final float textCacheRight =
+ Math.min(left + layout.getLineRight(0) + mPaddingH, mScrollX + mRight - mLeft) +
+ getCacheRightPadding();
+ final float textCacheBottom = top + layout.getLineBottom(0) + mPaddingV +
+ getCacheBottomPadding();
+ final float xCharWidth = getPaint().measureText("x");
+
+ int width = (int) (textCacheRight - mTextCacheLeft + (2 * xCharWidth));
+ int height = (int) (textCacheBottom - mTextCacheTop);
+
+ if (width != 0 && height != 0) {
+ if (mCache != null) {
+ if (mCache.getWidth() != width || mCache.getHeight() != height) {
+ mCache.recycle();
+ mCache = null;
+ }
+ }
+ if (mCache == null) {
+ mCache = Bitmap.createBitmap(width, height, Config.ARGB_8888);
+ mCacheCanvas.setBitmap(mCache);
+ } else {
+ mCacheCanvas.drawColor(0, Mode.CLEAR);
+ }
+
+ mCacheCanvas.save();
+ mCacheCanvas.translate(-mTextCacheLeft, -mTextCacheTop);
+
+ mIsBuildingCache = true;
+ setAlpha(1.0f);
+ draw(mCacheCanvas);
+ setAlpha(prevAlpha);
+ mIsBuildingCache = false;
+ mCacheCanvas.restore();
+
+ // A hack-- we set the text to be one space (we don't make it empty just to avoid any
+ // potential issues with text measurement, like line height, etc.) so that the text view
+ // doesn't draw it anymore, since it's been cached.
+ mText = getText();
+ setText(" ");
+ }
+ }
+
+ public CharSequence getText() {
+ return (mText == null) ? super.getText() : mText;
+ }
+
+ public void draw(Canvas canvas) {
+ if (mIsTextCacheDirty && !mIsBuildingCache) {
+ buildAndUpdateCache();
+ mIsTextCacheDirty = false;
+ }
+ if (mCache != null && !mIsBuildingCache) {
+ canvas.drawBitmap(mCache, mTextCacheLeft - mTextCacheScrollX + mScrollX,
+ mTextCacheTop, mCachePaint);
+ }
+ super.draw(canvas);
+ }
+
+ protected boolean isBuildingCache() {
+ return mIsBuildingCache;
+ }
+
+ @Override
+ protected boolean onSetAlpha(int alpha) {
+ if (mPrevAlpha != alpha) {
+ mPrevAlpha = alpha;
+ mCachePaint.setAlpha(alpha);
+ super.onSetAlpha(alpha);
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 9d39c2c..49ae652 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -16,54 +16,131 @@
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.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.WallpaperManager;
import android.content.Context;
-import android.content.res.TypedArray;
import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.graphics.Canvas;
+import android.graphics.Region;
+import android.graphics.Bitmap.Config;
+import android.graphics.PorterDuff.Mode;
+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;
import android.view.ViewGroup;
-import android.app.WallpaperManager;
+import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LayoutAnimationController;
-import java.util.ArrayList;
+import java.util.Arrays;
-import com.android.launcher.R;
-
-public class CellLayout extends ViewGroup {
- private boolean mPortrait;
+public class CellLayout extends ViewGroup implements VisibilityChangedListener {
+ static final String TAG = "CellLayout";
private int mCellWidth;
private int mCellHeight;
-
- private int mLongAxisStartPadding;
- private int mLongAxisEndPadding;
- private int mShortAxisStartPadding;
- private int mShortAxisEndPadding;
+ private int mLeftPadding;
+ private int mRightPadding;
+ private int mTopPadding;
+ private int mBottomPadding;
- private int mShortAxisCells;
- private int mLongAxisCells;
+ private int mCountX;
+ private int mCountY;
private int mWidthGap;
private int mHeightGap;
private final Rect mRect = new Rect();
private final CellInfo mCellInfo = new CellInfo();
-
- int[] mCellXY = new int[2];
+
+ // These are temporary variables to prevent having to allocate a new object just to
+ // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
+ private final int[] mTmpCellXY = new int[2];
+ private final int[] mTmpPoint = new int[2];
+ private final PointF mTmpPointF = new PointF();
+
boolean[][] mOccupied;
- private RectF mDragRect = new RectF();
+ private OnTouchListener mInterceptTouchListener;
- private boolean mDirtyTag;
- private boolean mLastDownOnOccupiedCell = false;
-
- private final WallpaperManager mWallpaperManager;
+ private float mBackgroundAlpha;
+ private float mBackgroundAlphaMultiplier = 1.0f;
+
+ private Drawable mNormalBackground;
+ private Drawable mNormalGlowBackground;
+ private Drawable mActiveBackground;
+ private Drawable mActiveGlowBackground;
+ private Drawable mNormalBackgroundMini;
+ private Drawable mNormalGlowBackgroundMini;
+ private Drawable mActiveBackgroundMini;
+ private Drawable mActiveGlowBackgroundMini;
+ private Rect mBackgroundRect;
+ private Rect mGlowBackgroundRect;
+ private float mGlowBackgroundScale;
+ private float mGlowBackgroundAlpha;
+
+ private Bitmap mCache;
+ private Canvas mCacheCanvas;
+ private Rect mCacheRect;
+ private Paint mCachePaint;
+
+ private boolean mIsCacheEnabled = true;
+ private boolean mDisableCacheUpdates = false;
+ private boolean mForceCacheUpdate = false;
+ private boolean mIsCacheDirty = true;
+ private float mBitmapCacheScale;
+ private float mMaxScaleForUsingBitmapCache;
+
+ private boolean mAcceptsDrops = false;
+ // If we're actively dragging something over this screen, mIsDragOverlapping is true
+ private boolean mIsDragOverlapping = false;
+ private boolean mIsDragOccuring = false;
+ private boolean mIsDefaultDropTarget = false;
+ private final Point mDragCenter = new Point();
+
+ // 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 float[] mDragOutlineAlphas = new float[mDragOutlines.length];
+ private InterruptibleInOutAnimator[] mDragOutlineAnims =
+ new InterruptibleInOutAnimator[mDragOutlines.length];
+
+ // Used as an index into the above 3 arrays; indicates which is the most current value.
+ private int mDragOutlineCurrent = 0;
+ private final Paint mDragOutlinePaint = new Paint();
+
+ private Drawable mCrosshairsDrawable = null;
+ private InterruptibleInOutAnimator mCrosshairsAnimator = null;
+ private float mCrosshairsVisibility = 0.0f;
+
+ // When a drag operation is in progress, holds the nearest cell to the touch point
+ private final int[] mDragCell = new int[2];
+
+ private final WallpaperManager mWallpaperManager;
+
+ private boolean mDragging = false;
+
+ private TimeInterpolator mEaseOutInterpolator;
public CellLayout(Context context) {
this(context, null);
@@ -75,41 +152,420 @@
public CellLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+
+ // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
+ // the user where a dragged item will land when dropped.
+ setWillNotDraw(false);
+
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
-
- mLongAxisStartPadding =
- a.getDimensionPixelSize(R.styleable.CellLayout_longAxisStartPadding, 10);
- mLongAxisEndPadding =
- a.getDimensionPixelSize(R.styleable.CellLayout_longAxisEndPadding, 10);
- mShortAxisStartPadding =
- a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisStartPadding, 10);
- mShortAxisEndPadding =
- a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisEndPadding, 10);
-
- mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4);
- mLongAxisCells = a.getInt(R.styleable.CellLayout_longAxisCells, 4);
+ mWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, -1);
+ mHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, -1);
+
+ mLeftPadding =
+ a.getDimensionPixelSize(R.styleable.CellLayout_xAxisStartPadding, 10);
+ mRightPadding =
+ a.getDimensionPixelSize(R.styleable.CellLayout_xAxisEndPadding, 10);
+ mTopPadding =
+ a.getDimensionPixelSize(R.styleable.CellLayout_yAxisStartPadding, 10);
+ mBottomPadding =
+ a.getDimensionPixelSize(R.styleable.CellLayout_yAxisEndPadding, 10);
+
+ mCountX = LauncherModel.getCellCountX();
+ mCountY = LauncherModel.getCellCountY();
+ mOccupied = new boolean[mCountX][mCountY];
a.recycle();
setAlwaysDrawnWithCacheEnabled(false);
- if (mOccupied == null) {
- if (mPortrait) {
- mOccupied = new boolean[mShortAxisCells][mLongAxisCells];
- } else {
- mOccupied = new boolean[mLongAxisCells][mShortAxisCells];
+ mWallpaperManager = WallpaperManager.getInstance(context);
+
+ final Resources res = getResources();
+
+ if (LauncherApplication.isScreenXLarge()) {
+ mNormalBackground = res.getDrawable(R.drawable.homescreen_large_blue);
+ mNormalGlowBackground = res.getDrawable(R.drawable.homescreen_large_blue_strong);
+ mActiveBackground = res.getDrawable(R.drawable.homescreen_large_green);
+ mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_large_green_strong);
+
+ mNormalBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue);
+ mNormalGlowBackgroundMini = res.getDrawable(R.drawable.homescreen_small_blue_strong);
+ mActiveBackgroundMini = res.getDrawable(R.drawable.homescreen_small_green);
+ mActiveGlowBackgroundMini = res.getDrawable(R.drawable.homescreen_small_green_strong);
+
+ mNormalBackground.setFilterBitmap(true);
+ mNormalGlowBackground.setFilterBitmap(true);
+ mActiveBackground.setFilterBitmap(true);
+ mActiveGlowBackground.setFilterBitmap(true);
+ mNormalBackgroundMini.setFilterBitmap(true);
+ mNormalGlowBackgroundMini.setFilterBitmap(true);
+ mActiveBackgroundMini.setFilterBitmap(true);
+ mActiveGlowBackgroundMini.setFilterBitmap(true);
+ }
+
+ // Initialize the data structures used for the drag visualization.
+
+ mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
+ mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
+
+ // Set up the animation for fading the crosshairs in and out
+ int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
+ mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration, 0.0f, 1.0f);
+ mCrosshairsAnimator.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
+ invalidate();
+ }
+ });
+ mCrosshairsAnimator.getAnimator().setInterpolator(mEaseOutInterpolator);
+
+ for (int i = 0; i < mDragOutlines.length; i++) {
+ mDragOutlines[i] = new Point(-1, -1);
+ }
+
+ // When dragging things around the home screens, we show a green outline of
+ // where the item will land. The outlines gradually fade out, leaving a trail
+ // behind the drag path.
+ // Set up all the animations that are used to implement this fading.
+ final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
+ final float fromAlphaValue = 0;
+ final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
+
+ Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
+
+ for (int i = 0; i < mDragOutlineAnims.length; i++) {
+ final InterruptibleInOutAnimator anim =
+ new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
+ anim.getAnimator().setInterpolator(mEaseOutInterpolator);
+ final int thisIndex = i;
+ anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final Bitmap outline = (Bitmap)anim.getTag();
+
+ // If an animation is started and then stopped very quickly, we can still
+ // get spurious updates we've cleared the tag. Guard against this.
+ if (outline == null) {
+ if (false) {
+ Object val = animation.getAnimatedValue();
+ Log.d(TAG, "anim " + thisIndex + " update: " + val +
+ ", isStopped " + anim.isStopped());
+ }
+ // Try to prevent it from continuing to run
+ animation.cancel();
+ } else {
+ mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
+ final int left = mDragOutlines[thisIndex].x;
+ final int top = mDragOutlines[thisIndex].y;
+ CellLayout.this.invalidate(left, top,
+ left + outline.getWidth(), top + outline.getHeight());
+ }
+ }
+ });
+ // The animation holds a reference to the drag outline bitmap as long is it's
+ // running. This way the bitmap can be GCed when the animations are complete.
+ anim.getAnimator().addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
+ anim.setTag(null);
+ }
+ }
+ });
+ mDragOutlineAnims[i] = anim;
+ }
+
+ mBackgroundRect = new Rect();
+ mGlowBackgroundRect = new Rect();
+ mCacheRect = new Rect();
+ setHoverScale(1.0f);
+ setHoverAlpha(1.0f);
+
+ mBitmapCacheScale =
+ res.getInteger(R.integer.config_workspaceScreenBitmapCacheScale) / 100.0f;
+ mMaxScaleForUsingBitmapCache =
+ res.getInteger(R.integer.config_maxScaleForUsingWorkspaceScreenBitmapCache) / 100.0f;
+ mCacheCanvas = new Canvas();
+ }
+
+ public void setIsDefaultDropTarget(boolean isDefaultDropTarget) {
+ if (mIsDefaultDropTarget != isDefaultDropTarget) {
+ mIsDefaultDropTarget = isDefaultDropTarget;
+ invalidate();
+ }
+ }
+
+ void setIsDragOccuring(boolean isDragOccuring) {
+ if (mIsDragOccuring != isDragOccuring) {
+ mIsDragOccuring = isDragOccuring;
+ invalidate();
+ }
+ }
+
+ void setIsDragOverlapping(boolean isDragOverlapping) {
+ if (mIsDragOverlapping != isDragOverlapping) {
+ mIsDragOverlapping = isDragOverlapping;
+ invalidate();
+ }
+ }
+
+ boolean getIsDragOverlapping() {
+ return mIsDragOverlapping;
+ }
+
+ private void updateGlowRect() {
+ float marginFraction = (mGlowBackgroundScale - 1.0f) / 2.0f;
+ int marginX = (int) (marginFraction * (mBackgroundRect.right - mBackgroundRect.left));
+ int marginY = (int) (marginFraction * (mBackgroundRect.bottom - mBackgroundRect.top));
+ mGlowBackgroundRect.set(mBackgroundRect.left - marginX, mBackgroundRect.top - marginY,
+ mBackgroundRect.right + marginX, mBackgroundRect.bottom + marginY);
+ invalidate();
+ }
+
+ public void setHoverScale(float scaleFactor) {
+ if (scaleFactor != mGlowBackgroundScale) {
+ mGlowBackgroundScale = scaleFactor;
+ updateGlowRect();
+ }
+ }
+
+ public float getHoverScale() {
+ return mGlowBackgroundScale;
+ }
+
+ public float getHoverAlpha() {
+ return mGlowBackgroundAlpha;
+ }
+
+ public void setHoverAlpha(float alpha) {
+ mGlowBackgroundAlpha = alpha;
+ invalidate();
+ }
+
+ void animateDrop() {
+ if (LauncherApplication.isScreenXLarge()) {
+ Resources res = getResources();
+ float onDropScale = res.getInteger(R.integer.config_screenOnDropScalePercent) / 100.0f;
+ ObjectAnimator scaleUp = ObjectAnimator.ofFloat(this, "hoverScale", onDropScale);
+ scaleUp.setDuration(res.getInteger(R.integer.config_screenOnDropScaleUpDuration));
+ ObjectAnimator scaleDown = ObjectAnimator.ofFloat(this, "hoverScale", 1.0f);
+ scaleDown.setDuration(res.getInteger(R.integer.config_screenOnDropScaleDownDuration));
+ ObjectAnimator alphaFadeOut = ObjectAnimator.ofFloat(this, "hoverAlpha", 0.0f);
+
+ alphaFadeOut.setStartDelay(res.getInteger(R.integer.config_screenOnDropAlphaFadeDelay));
+ alphaFadeOut.setDuration(res.getInteger(R.integer.config_screenOnDropAlphaFadeDelay));
+
+ AnimatorSet bouncer = new AnimatorSet();
+ bouncer.play(scaleUp).before(scaleDown);
+ bouncer.play(scaleUp).with(alphaFadeOut);
+ bouncer.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ setIsDragOverlapping(true);
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setIsDragOverlapping(false);
+ setHoverScale(1.0f);
+ setHoverAlpha(1.0f);
+ }
+ });
+ bouncer.start();
+ }
+ }
+
+ public void drawChildren(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ }
+
+ private void invalidateIfNeeded() {
+ if (mIsCacheDirty) {
+ // Force a redraw to update the cache if it's dirty
+ invalidate();
+ }
+ }
+
+ public void enableCache() {
+ mIsCacheEnabled = true;
+ invalidateIfNeeded();
+ }
+
+ public void disableCache() {
+ mIsCacheEnabled = false;
+ }
+
+ public void disableCacheUpdates() {
+ mDisableCacheUpdates = true;
+ // Force just one update before we enter a period of no cache updates
+ mForceCacheUpdate = true;
+ }
+
+ public void enableCacheUpdates() {
+ mDisableCacheUpdates = false;
+ invalidateIfNeeded();
+ }
+
+ private void invalidateCache() {
+ mIsCacheDirty = true;
+ invalidate();
+ }
+
+ public void receiveVisibilityChangedMessage(View v) {
+ invalidateCache();
+ }
+
+ public void updateCache() {
+ mCacheCanvas.drawColor(0, Mode.CLEAR);
+
+ float alpha = getAlpha();
+ setAlpha(1.0f);
+ drawChildren(mCacheCanvas);
+ setAlpha(alpha);
+
+ mIsCacheDirty = false;
+ }
+
+ public void dispatchDraw(Canvas canvas) {
+ final int count = getChildCount();
+
+ if (!mIsCacheDirty) {
+ // Check if one of the children (an icon or widget) is dirty
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.isDirty()) {
+ mIsCacheDirty = true;
+ break;
+ }
}
}
-
- mWallpaperManager = WallpaperManager.getInstance(getContext());
+
+ boolean useBitmapCache = mIsCacheEnabled && getScaleX() < mMaxScaleForUsingBitmapCache;
+ if (mForceCacheUpdate ||
+ (useBitmapCache && !mDisableCacheUpdates)) {
+ // Sometimes we force a cache update-- this is used to make sure the cache will look as
+ // up-to-date as possible right when we disable cache updates
+ if (mIsCacheDirty) {
+ updateCache();
+ }
+ mForceCacheUpdate = false;
+ }
+
+ if (useBitmapCache) {
+ mCachePaint.setAlpha((int)(255*getAlpha()));
+ canvas.drawBitmap(mCache, mCacheRect, mBackgroundRect, mCachePaint);
+ } else {
+ super.dispatchDraw(canvas);
+ }
+ }
+
+ private void prepareCacheBitmap() {
+ if (mCache == null) {
+ mCache = Bitmap.createBitmap((int) (getWidth() * mBitmapCacheScale),
+ (int) (getHeight() * mBitmapCacheScale), Config.ARGB_8888);
+
+ mCachePaint = new Paint();
+ mCachePaint.setFilterBitmap(true);
+ mCacheCanvas.setBitmap(mCache);
+ mCacheCanvas.scale(mBitmapCacheScale, mBitmapCacheScale);
+ }
}
@Override
- public void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
+ protected void onDraw(Canvas canvas) {
+ // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
+ // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
+ // 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) {
+ Drawable bg;
+ boolean mini = getScaleX() < 0.5f;
+
+ if (mIsDragOverlapping) {
+ // In the mini case, we draw the active_glow bg *over* the active background
+ bg = mini ? mActiveBackgroundMini : mActiveGlowBackground;
+ } else if (mIsDragOccuring && mAcceptsDrops) {
+ bg = mini ? mActiveBackgroundMini : mActiveBackground;
+ } else if (mIsDragOccuring && mIsDefaultDropTarget) {
+ bg = mini ? mNormalGlowBackgroundMini : mNormalGlowBackground;
+ } else {
+ bg = mini ? mNormalBackgroundMini : mNormalBackground;
+ }
+
+ bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
+ bg.setBounds(mBackgroundRect);
+ bg.draw(canvas);
+
+ if (mini && mIsDragOverlapping) {
+ boolean modifiedClipRect = false;
+ if (mGlowBackgroundScale > 1.0f) {
+ // If the hover background's scale is greater than 1, we'll be drawing outside
+ // the bounds of this CellLayout. Get around that by temporarily increasing the
+ // size of the clip rect
+ float marginFraction = (mGlowBackgroundScale - 1.0f) / 2.0f;
+ Rect clipRect = canvas.getClipBounds();
+ int marginX = (int) (marginFraction * (clipRect.right - clipRect.left));
+ int marginY = (int) (marginFraction * (clipRect.bottom - clipRect.top));
+ canvas.save(Canvas.CLIP_SAVE_FLAG);
+ canvas.clipRect(-marginX, -marginY,
+ getWidth() + marginX, getHeight() + marginY, Region.Op.REPLACE);
+ modifiedClipRect = true;
+ }
+
+ mActiveGlowBackgroundMini.setAlpha(
+ (int) (mBackgroundAlpha * mGlowBackgroundAlpha * 255));
+ mActiveGlowBackgroundMini.setBounds(mGlowBackgroundRect);
+ mActiveGlowBackgroundMini.draw(canvas);
+ if (modifiedClipRect) {
+ canvas.restore();
+ }
+ }
+ }
+
+ if (mCrosshairsVisibility > 0.0f) {
+ final int countX = mCountX;
+ final int countY = mCountY;
+
+ final float MAX_ALPHA = 0.4f;
+ final int MAX_VISIBLE_DISTANCE = 600;
+ final float DISTANCE_MULTIPLIER = 0.002f;
+
+ final Drawable d = mCrosshairsDrawable;
+ final int width = d.getIntrinsicWidth();
+ final int height = d.getIntrinsicHeight();
+
+ int x = getLeftPadding() - (mWidthGap / 2) - (width / 2);
+ for (int col = 0; col <= countX; col++) {
+ int y = getTopPadding() - (mHeightGap / 2) - (height / 2);
+ for (int row = 0; row <= countY; row++) {
+ mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y);
+ float dist = mTmpPointF.length();
+ // Crosshairs further from the drag point are more faint
+ float alpha = Math.min(MAX_ALPHA,
+ DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist));
+ if (alpha > 0.0f) {
+ d.setBounds(x, y, x + width, y + height);
+ d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility));
+ d.draw(canvas);
+ }
+ y += mCellHeight + mHeightGap;
+ }
+ x += mCellWidth + mWidthGap;
+ }
+ }
+
+ final Paint paint = mDragOutlinePaint;
+ for (int i = 0; i < mDragOutlines.length; i++) {
+ final float alpha = mDragOutlineAlphas[i];
+ if (alpha > 0) {
+ final Point p = mDragOutlines[i];
+ final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
+ paint.setAlpha((int)(alpha + .5f));
+ canvas.drawBitmap(b, p.x, p.y, paint);
+ }
+ }
}
@Override
@@ -124,22 +580,119 @@
}
}
+ public void setOnInterceptTouchListener(View.OnTouchListener listener) {
+ mInterceptTouchListener = listener;
+ }
+
int getCountX() {
- return mPortrait ? mShortAxisCells : mLongAxisCells;
+ return mCountX;
}
int getCountY() {
- return mPortrait ? mLongAxisCells : mShortAxisCells;
+ return mCountY;
+ }
+
+ public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params) {
+ return addViewToCellLayout(child, index, childId, params, true);
+ }
+
+ public boolean addViewToCellLayout(
+ View child, int index, int childId, LayoutParams params, boolean markCells) {
+ final LayoutParams lp = params;
+
+ // Generate an id for each view, this assumes we have at most 256x256 cells
+ // per workspace screen
+ if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
+ // If the horizontal or vertical span is set to -1, it is taken to
+ // mean that it spans the extent of the CellLayout
+ if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
+ if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
+
+ child.setId(childId);
+
+ addView(child, index, lp);
+ child.setAlpha(getAlpha());
+ if (child instanceof VisibilityChangedBroadcaster) {
+ VisibilityChangedBroadcaster v = (VisibilityChangedBroadcaster) child;
+ v.setVisibilityChangedListener(this);
+ }
+
+ // invalidate the cache to have it reflect the new item
+ invalidateCache();
+ if (markCells) markCellsAsOccupiedForView(child);
+
+ return true;
+ }
+ return false;
+ }
+
+ public void setAcceptsDrops(boolean acceptsDrops) {
+ if (mAcceptsDrops != acceptsDrops) {
+ mAcceptsDrops = acceptsDrops;
+ invalidate();
+ }
+ }
+
+ public boolean getAcceptsDrops() {
+ return mAcceptsDrops;
}
@Override
- public void addView(View child, int index, ViewGroup.LayoutParams params) {
- // Generate an id for each view, this assumes we have at most 256x256 cells
- // per workspace screen
- final LayoutParams cellParams = (LayoutParams) params;
- cellParams.regenerateId = true;
+ public void removeAllViews() {
+ super.removeAllViews();
+ clearOccupiedCells();
+ invalidateCache();
+ }
- super.addView(child, index, params);
+ @Override
+ public void removeAllViewsInLayout() {
+ super.removeAllViewsInLayout();
+ clearOccupiedCells();
+ invalidateCache();
+ }
+
+ public void removeViewWithoutMarkingCells(View view) {
+ super.removeView(view);
+ invalidateCache();
+ }
+
+ @Override
+ public void removeView(View view) {
+ markCellsAsUnoccupiedForView(view);
+ super.removeView(view);
+ invalidateCache();
+ }
+
+ @Override
+ public void removeViewAt(int index) {
+ markCellsAsUnoccupiedForView(getChildAt(index));
+ super.removeViewAt(index);
+ invalidateCache();
+ }
+
+ @Override
+ public void removeViewInLayout(View view) {
+ markCellsAsUnoccupiedForView(view);
+ super.removeViewInLayout(view);
+ invalidateCache();
+ }
+
+ @Override
+ public void removeViews(int start, int count) {
+ for (int i = start; i < start + count; i++) {
+ markCellsAsUnoccupiedForView(getChildAt(i));
+ }
+ super.removeViews(start, count);
+ invalidateCache();
+ }
+
+ @Override
+ public void removeViewsInLayout(int start, int count) {
+ for (int i = start; i < start + count; i++) {
+ markCellsAsUnoccupiedForView(getChildAt(i));
+ }
+ super.removeViewsInLayout(start, count);
+ invalidateCache();
}
@Override
@@ -158,67 +711,59 @@
mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
}
+ public void setTagToCellInfoForPoint(int touchX, int touchY) {
+ final CellInfo cellInfo = mCellInfo;
+ final Rect frame = mRect;
+ final int x = touchX + mScrollX;
+ final int y = touchY + mScrollY;
+ final int count = getChildCount();
+
+ boolean found = false;
+ for (int i = count - 1; i >= 0; i--) {
+ final View child = getChildAt(i);
+
+ if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
+ child.getHitRect(frame);
+ if (frame.contains(x, y)) {
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ cellInfo.cell = child;
+ cellInfo.cellX = lp.cellX;
+ cellInfo.cellY = lp.cellY;
+ cellInfo.spanX = lp.cellHSpan;
+ cellInfo.spanY = lp.cellVSpan;
+ cellInfo.valid = true;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ final int cellXY[] = mTmpCellXY;
+ pointToCellExact(x, y, cellXY);
+
+ cellInfo.cell = null;
+ cellInfo.cellX = cellXY[0];
+ cellInfo.cellY = cellXY[1];
+ cellInfo.spanX = 1;
+ cellInfo.spanY = 1;
+ cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < mCountX &&
+ cellXY[1] < mCountY && !mOccupied[cellXY[0]][cellXY[1]];
+ }
+ setTag(cellInfo);
+ }
+
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
+ return true;
+ }
final int action = ev.getAction();
final CellInfo cellInfo = mCellInfo;
if (action == MotionEvent.ACTION_DOWN) {
- final Rect frame = mRect;
- final int x = (int) ev.getX() + mScrollX;
- final int y = (int) ev.getY() + mScrollY;
- final int count = getChildCount();
-
- boolean found = false;
- for (int i = count - 1; i >= 0; i--) {
- final View child = getChildAt(i);
-
- if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
- child.getHitRect(frame);
- if (frame.contains(x, y)) {
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- cellInfo.cell = child;
- cellInfo.cellX = lp.cellX;
- cellInfo.cellY = lp.cellY;
- cellInfo.spanX = lp.cellHSpan;
- cellInfo.spanY = lp.cellVSpan;
- cellInfo.valid = true;
- found = true;
- mDirtyTag = false;
- break;
- }
- }
- }
-
- mLastDownOnOccupiedCell = found;
-
- if (!found) {
- int cellXY[] = mCellXY;
- pointToCellExact(x, y, cellXY);
-
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
-
- final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied, null);
-
- cellInfo.cell = null;
- cellInfo.cellX = cellXY[0];
- cellInfo.cellY = cellXY[1];
- cellInfo.spanX = 1;
- cellInfo.spanY = 1;
- cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount &&
- cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]];
-
- // Instead of finding the interesting vacant cells here, wait until a
- // caller invokes getTag() to retrieve the result. Finding the vacant
- // cells is a bit expensive and can generate many new objects, it's
- // therefore better to defer it until we know we actually need it.
-
- mDirtyTag = true;
- }
- setTag(cellInfo);
+ setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
} else if (action == MotionEvent.ACTION_UP) {
cellInfo.cell = null;
cellInfo.cellX = -1;
@@ -226,7 +771,6 @@
cellInfo.spanX = 0;
cellInfo.spanY = 0;
cellInfo.valid = false;
- mDirtyTag = false;
setTag(cellInfo);
}
@@ -235,186 +779,31 @@
@Override
public CellInfo getTag() {
- final CellInfo info = (CellInfo) super.getTag();
- if (mDirtyTag && info.valid) {
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
-
- final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied, null);
-
- findIntersectingVacantCells(info, info.cellX, info.cellY, xCount, yCount, occupied);
-
- mDirtyTag = false;
- }
- return info;
- }
-
- private static void findIntersectingVacantCells(CellInfo cellInfo, int x, int y,
- int xCount, int yCount, boolean[][] occupied) {
-
- cellInfo.maxVacantSpanX = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanY = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE;
- cellInfo.clearVacantCells();
-
- if (occupied[x][y]) {
- return;
- }
-
- cellInfo.current.set(x, y, x, y);
-
- findVacantCell(cellInfo.current, xCount, yCount, occupied, cellInfo);
- }
-
- private static void findVacantCell(Rect current, int xCount, int yCount, boolean[][] occupied,
- CellInfo cellInfo) {
-
- addVacantCell(current, cellInfo);
-
- if (current.left > 0) {
- if (isColumnEmpty(current.left - 1, current.top, current.bottom, occupied)) {
- current.left--;
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- current.left++;
- }
- }
-
- if (current.right < xCount - 1) {
- if (isColumnEmpty(current.right + 1, current.top, current.bottom, occupied)) {
- current.right++;
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- current.right--;
- }
- }
-
- if (current.top > 0) {
- if (isRowEmpty(current.top - 1, current.left, current.right, occupied)) {
- current.top--;
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- current.top++;
- }
- }
-
- if (current.bottom < yCount - 1) {
- if (isRowEmpty(current.bottom + 1, current.left, current.right, occupied)) {
- current.bottom++;
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- current.bottom--;
- }
- }
- }
-
- private static void addVacantCell(Rect current, CellInfo cellInfo) {
- CellInfo.VacantCell cell = CellInfo.VacantCell.acquire();
- cell.cellX = current.left;
- cell.cellY = current.top;
- cell.spanX = current.right - current.left + 1;
- cell.spanY = current.bottom - current.top + 1;
- if (cell.spanX > cellInfo.maxVacantSpanX) {
- cellInfo.maxVacantSpanX = cell.spanX;
- cellInfo.maxVacantSpanXSpanY = cell.spanY;
- }
- if (cell.spanY > cellInfo.maxVacantSpanY) {
- cellInfo.maxVacantSpanY = cell.spanY;
- cellInfo.maxVacantSpanYSpanX = cell.spanX;
- }
- cellInfo.vacantCells.add(cell);
- }
-
- private static boolean isColumnEmpty(int x, int top, int bottom, boolean[][] occupied) {
- for (int y = top; y <= bottom; y++) {
- if (occupied[x][y]) {
- return false;
- }
- }
- return true;
- }
-
- private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) {
- for (int x = left; x <= right; x++) {
- if (occupied[x][y]) {
- return false;
- }
- }
- return true;
- }
-
- CellInfo findAllVacantCells(boolean[] occupiedCells, View ignoreView) {
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
-
- boolean[][] occupied = mOccupied;
-
- if (occupiedCells != null) {
- for (int y = 0; y < yCount; y++) {
- for (int x = 0; x < xCount; x++) {
- occupied[x][y] = occupiedCells[y * xCount + x];
- }
- }
- } else {
- findOccupiedCells(xCount, yCount, occupied, ignoreView);
- }
-
- CellInfo cellInfo = new CellInfo();
-
- cellInfo.cellX = -1;
- cellInfo.cellY = -1;
- cellInfo.spanY = 0;
- cellInfo.spanX = 0;
- cellInfo.maxVacantSpanX = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanY = Integer.MIN_VALUE;
- cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE;
- cellInfo.screen = mCellInfo.screen;
-
- Rect current = cellInfo.current;
-
- for (int x = 0; x < xCount; x++) {
- for (int y = 0; y < yCount; y++) {
- if (!occupied[x][y]) {
- current.set(x, y, x, y);
- findVacantCell(current, xCount, yCount, occupied, cellInfo);
- occupied[x][y] = true;
- }
- }
- }
-
- cellInfo.valid = cellInfo.vacantCells.size() > 0;
-
- // Assume the caller will perform their own cell searching, otherwise we
- // risk causing an unnecessary rebuild after findCellForSpan()
-
- return cellInfo;
+ return (CellInfo) super.getTag();
}
/**
- * Given a point, return the cell that strictly encloses that point
+ * Given a point, return the cell that strictly encloses that point
* @param x X coordinate of the point
* @param y Y coordinate of the point
* @param result Array of 2 ints to hold the x and y coordinate of the cell
*/
void pointToCellExact(int x, int y, int[] result) {
- final boolean portrait = mPortrait;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
+ final int hStartPadding = getLeftPadding();
+ final int vStartPadding = getTopPadding();
result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
- final int xAxis = portrait ? mShortAxisCells : mLongAxisCells;
- final int yAxis = portrait ? mLongAxisCells : mShortAxisCells;
+ final int xAxis = mCountX;
+ final int yAxis = mCountY;
if (result[0] < 0) result[0] = 0;
if (result[0] >= xAxis) result[0] = xAxis - 1;
if (result[1] < 0) result[1] = 0;
if (result[1] >= yAxis) result[1] = yAxis - 1;
}
-
+
/**
* Given a point, return the cell that most closely encloses that point
* @param x X coordinate of the point
@@ -427,18 +816,15 @@
/**
* Given a cell coordinate, return the point that represents the upper left corner of that cell
- *
- * @param cellX X coordinate of the 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 cellToPoint(int cellX, int cellY, int[] result) {
- final boolean portrait = mPortrait;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-
+ final int hStartPadding = getLeftPadding();
+ final int vStartPadding = getTopPadding();
result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
@@ -453,101 +839,76 @@
}
int getLeftPadding() {
- return mPortrait ? mShortAxisStartPadding : mLongAxisStartPadding;
+ return mLeftPadding;
}
int getTopPadding() {
- return mPortrait ? mLongAxisStartPadding : mShortAxisStartPadding;
+ return mTopPadding;
}
int getRightPadding() {
- return mPortrait ? mShortAxisEndPadding : mLongAxisEndPadding;
+ return mRightPadding;
}
int getBottomPadding() {
- return mPortrait ? mLongAxisEndPadding : mShortAxisEndPadding;
+ return mBottomPadding;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO: currently ignoring padding
-
+
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
+
if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
}
- final int shortAxisCells = mShortAxisCells;
- final int longAxisCells = mLongAxisCells;
- final int longAxisStartPadding = mLongAxisStartPadding;
- final int longAxisEndPadding = mLongAxisEndPadding;
- final int shortAxisStartPadding = mShortAxisStartPadding;
- final int shortAxisEndPadding = mShortAxisEndPadding;
final int cellWidth = mCellWidth;
final int cellHeight = mCellHeight;
- mPortrait = heightSpecSize > widthSpecSize;
+ int numWidthGaps = mCountX - 1;
+ int numHeightGaps = mCountY - 1;
- int numShortGaps = shortAxisCells - 1;
- int numLongGaps = longAxisCells - 1;
+ if (mWidthGap < 0 || mHeightGap < 0) {
+ int vSpaceLeft = heightSpecSize - mTopPadding - mBottomPadding - (cellHeight * mCountY);
+ mHeightGap = vSpaceLeft / numHeightGaps;
- if (mPortrait) {
- int vSpaceLeft = heightSpecSize - longAxisStartPadding - longAxisEndPadding
- - (cellHeight * longAxisCells);
- mHeightGap = vSpaceLeft / numLongGaps;
+ int hSpaceLeft = widthSpecSize - mLeftPadding - mRightPadding - (cellWidth * mCountX);
+ mWidthGap = hSpaceLeft / numWidthGaps;
- int hSpaceLeft = widthSpecSize - shortAxisStartPadding - shortAxisEndPadding
- - (cellWidth * shortAxisCells);
- if (numShortGaps > 0) {
- mWidthGap = hSpaceLeft / numShortGaps;
- } else {
- mWidthGap = 0;
- }
- } else {
- int hSpaceLeft = widthSpecSize - longAxisStartPadding - longAxisEndPadding
- - (cellWidth * longAxisCells);
- mWidthGap = hSpaceLeft / numLongGaps;
-
- int vSpaceLeft = heightSpecSize - shortAxisStartPadding - shortAxisEndPadding
- - (cellHeight * shortAxisCells);
- if (numShortGaps > 0) {
- mHeightGap = vSpaceLeft / numShortGaps;
- } else {
- mHeightGap = 0;
- }
+ // center it around the min gaps
+ int minGap = Math.min(mWidthGap, mHeightGap);
+ mWidthGap = mHeightGap = minGap;
}
-
+
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if (mPortrait) {
- lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, shortAxisStartPadding,
- longAxisStartPadding);
- } else {
- lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, longAxisStartPadding,
- shortAxisStartPadding);
- }
-
- if (lp.regenerateId) {
- child.setId(((getId() & 0xFF) << 16) | (lp.cellX & 0xFF) << 8 | (lp.cellY & 0xFF));
- lp.regenerateId = false;
- }
+ lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap,
+ mLeftPadding, mTopPadding);
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
- int childheightMeasureSpec =
- MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
+ int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
+ MeasureSpec.EXACTLY);
+
child.measure(childWidthMeasureSpec, childheightMeasureSpec);
}
-
- setMeasuredDimension(widthSpecSize, heightSpecSize);
+ if (widthSpecMode == MeasureSpec.AT_MOST) {
+ int newWidth = mLeftPadding + mRightPadding + (mCountX * cellWidth) +
+ ((mCountX - 1) * mWidthGap);
+ int newHeight = mTopPadding + mBottomPadding + (mCountY * cellHeight) +
+ ((mCountY - 1) * mHeightGap);
+ setMeasuredDimension(newWidth, newHeight);
+ } else if (widthSpecMode == MeasureSpec.EXACTLY) {
+ setMeasuredDimension(widthSpecSize, heightSpecSize);
+ }
}
@Override
@@ -555,7 +916,7 @@
int count = getChildCount();
for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
+ final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
@@ -567,14 +928,37 @@
if (lp.dropped) {
lp.dropped = false;
- final int[] cellXY = mCellXY;
+ final int[] cellXY = mTmpCellXY;
getLocationOnScreen(cellXY);
- mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.home.drop",
+ mWallpaperManager.sendWallpaperCommand(getWindowToken(),
+ WallpaperManager.COMMAND_DROP,
cellXY[0] + childLeft + lp.width / 2,
cellXY[1] + childTop + lp.height / 2, 0, null);
+
+ if (lp.animateDrop) {
+ lp.animateDrop = false;
+
+ // This call does not result in a requestLayout(), but at one point did.
+ // We need to be cautious about any method calls within the layout pass
+ // to insure we don't leave the view tree in a bad state.
+ ((Workspace) mParent).animateViewIntoPosition(child);
+ }
}
}
}
+ prepareCacheBitmap();
+ invalidateCache();
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mBackgroundRect.set(0, 0, w, h);
+ updateGlowRect();
+ mCacheRect.set(0, 0, (int) (mBitmapCacheScale * w), (int) (mBitmapCacheScale * h));
+ mCache = null;
+ prepareCacheBitmap();
+ invalidateCache();
}
@Override
@@ -584,7 +968,9 @@
final View view = getChildAt(i);
view.setDrawingCacheEnabled(enabled);
// Update the drawing caches
- view.buildDrawingCache(true);
+ if (!view.isHardwareAccelerated()) {
+ view.buildDrawingCache(true);
+ }
}
}
@@ -593,154 +979,441 @@
super.setChildrenDrawnWithCacheEnabled(enabled);
}
+ public float getBackgroundAlpha() {
+ return mBackgroundAlpha;
+ }
+
+ public void setBackgroundAlphaMultiplier(float multiplier) {
+ mBackgroundAlphaMultiplier = multiplier;
+ }
+
+ public float getBackgroundAlphaMultiplier() {
+ return mBackgroundAlphaMultiplier;
+ }
+
+ public void setBackgroundAlpha(float alpha) {
+ mBackgroundAlpha = alpha;
+ invalidate();
+ }
+
+ // Need to return true to let the view system know we know how to handle alpha-- this is
+ // because when our children have an alpha of 0.0f, they are still rendering their "dimmed"
+ // versions
+ @Override
+ protected boolean onSetAlpha(int alpha) {
+ return true;
+ }
+
+ 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);
+ }
+ }
+
+ public View getChildAt(int x, int y) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+ if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
+ (lp.cellY <= y) && (y < lp.cellY + lp.cellHSpan)) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Estimate where the top left cell of the dragged item will land if it is dropped.
+ *
+ * @param originX The X value of the top left corner of the item
+ * @param originY The Y value of the top left corner of the item
+ * @param spanX The number of horizontal cells that the item spans
+ * @param spanY The number of vertical cells that the item spans
+ * @param result The estimated drop cell X and Y.
+ */
+ void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
+ final int countX = mCountX;
+ final int countY = mCountY;
+
+ // pointToCellRounded takes the top left of a cell but will pad that with
+ // cellWidth/2 and cellHeight/2 when finding the matching cell
+ pointToCellRounded(originX, originY, result);
+
+ // If the item isn't fully on this screen, snap to the edges
+ int rightOverhang = result[0] + spanX - countX;
+ if (rightOverhang > 0) {
+ result[0] -= rightOverhang; // Snap to right
+ }
+ result[0] = Math.max(0, result[0]); // Snap to left
+ int bottomOverhang = result[1] + spanY - countY;
+ if (bottomOverhang > 0) {
+ result[1] -= bottomOverhang; // Snap to bottom
+ }
+ result[1] = Math.max(0, result[1]); // Snap to top
+ }
+
+ void visualizeDropLocation(
+ View v, Bitmap dragOutline, int originX, int originY, int spanX, int spanY) {
+
+ final int oldDragCellX = mDragCell[0];
+ final int oldDragCellY = mDragCell[1];
+ final int[] nearest = findNearestVacantArea(originX, originY, spanX, spanY, v, mDragCell);
+ if (v != null) {
+ mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2));
+ } else {
+ mDragCenter.set(originX, originY);
+ }
+
+ if (nearest != null && (nearest[0] != oldDragCellX || nearest[1] != oldDragCellY)) {
+ // Find the top left corner of the rect the object will occupy
+ final int[] topLeft = mTmpPoint;
+ cellToPoint(nearest[0], nearest[1], topLeft);
+
+ int left = topLeft[0];
+ int top = topLeft[1];
+
+ if (v != null) {
+ if (v.getParent() instanceof CellLayout) {
+ LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ left += lp.leftMargin;
+ top += lp.topMargin;
+ }
+
+ // Offsets due to the size difference between the View and the dragOutline
+ left += (v.getWidth() - dragOutline.getWidth()) / 2;
+ top += (v.getHeight() - dragOutline.getHeight()) / 2;
+ }
+
+ final int oldIndex = mDragOutlineCurrent;
+ mDragOutlineAnims[oldIndex].animateOut();
+ mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
+
+ mDragOutlines[mDragOutlineCurrent].set(left, top);
+ mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
+ mDragOutlineAnims[mDragOutlineCurrent].animateIn();
+ }
+
+ // If we are drawing crosshairs, the entire CellLayout needs to be invalidated
+ if (mCrosshairsDrawable != null) {
+ invalidate();
+ }
+ }
+
/**
* 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 vacantCells Pre-computed set of vacant cells to search.
- * @param recycle Previously returned value to possibly recycle.
+ * @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,
- CellInfo vacantCells, int[] recycle) {
-
+ int[] findNearestVacantArea(
+ int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+ return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
+ }
+
+ /**
+ * Find a vacant area that will fit the given bounds nearest the requested
+ * cell location. Uses Euclidean distance to score multiple vacant areas.
+ *
+ * @param pixelX The X location at which you want to search for a vacant area.
+ * @param pixelY The Y location at which you want to search for a vacant area.
+ * @param 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) {
+ // mark space take by ignoreView as available (method checks if ignoreView is null)
+ markCellsAsUnoccupiedForView(ignoreView);
+
// Keep track of best-scoring drop area
- final int[] bestXY = recycle != null ? recycle : new int[2];
- final int[] cellXY = mCellXY;
+ final int[] bestXY = result != null ? result : new int[2];
double bestDistance = Double.MAX_VALUE;
-
- // Bail early if vacant cells aren't valid
- if (!vacantCells.valid) {
- return null;
- }
- // Look across all vacant cells for best fit
- final int size = vacantCells.vacantCells.size();
- for (int i = 0; i < size; i++) {
- final CellInfo.VacantCell cell = vacantCells.vacantCells.get(i);
-
- // Reject if vacant cell isn't our exact size
- if (cell.spanX != spanX || cell.spanY != spanY) {
- continue;
- }
-
- // Score is center distance from requested pixel
- cellToPoint(cell.cellX, cell.cellY, cellXY);
-
- double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) +
- Math.pow(cellXY[1] - pixelY, 2));
- if (distance <= bestDistance) {
- bestDistance = distance;
- bestXY[0] = cell.cellX;
- bestXY[1] = cell.cellY;
+ final int countX = mCountX;
+ final int countY = mCountY;
+ final boolean[][] occupied = mOccupied;
+
+ 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;
+ }
+ }
+ }
+ final int[] cellXY = mTmpCellXY;
+ cellToPoint(x, y, cellXY);
+
+ double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
+ + Math.pow(cellXY[1] - pixelY, 2));
+ if (distance <= bestDistance) {
+ bestDistance = distance;
+ bestXY[0] = x;
+ bestXY[1] = y;
+ }
}
}
+ // re-mark space taken by ignoreView as occupied
+ markCellsAsOccupiedForView(ignoreView);
- // Return null if no suitable location found
+ // Return null if no suitable location found
if (bestDistance < Double.MAX_VALUE) {
return bestXY;
} else {
return null;
}
}
-
- /**
- * Drop a child at the specified position
- *
- * @param child The child that is being dropped
- * @param targetXY Destination area to move to
- */
- void onDropChild(View child, int[] targetXY) {
- if (child != null) {
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.cellX = targetXY[0];
- lp.cellY = targetXY[1];
- lp.isDragging = false;
- lp.dropped = true;
- mDragRect.setEmpty();
- child.requestLayout();
- invalidate();
- }
+
+ boolean existsEmptyCell() {
+ return findCellForSpan(null, 1, 1);
}
- void onDropAborted(View child) {
- if (child != null) {
- ((LayoutParams) child.getLayoutParams()).isDragging = false;
- invalidate();
+ /**
+ * Finds the upper-left coordinate of the first rectangle in the grid that can
+ * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
+ * then this method will only return coordinates for rectangles that contain the cell
+ * (intersectX, intersectY)
+ *
+ * @param cellXY The array that will contain the position of a vacant cell if such a cell
+ * can be found.
+ * @param spanX The horizontal span of the cell we want to find.
+ * @param spanY The vertical span of the cell we want to find.
+ *
+ * @return True if a vacant cell of the specified dimension was found, false otherwise.
+ */
+ boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
+ return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null);
+ }
+
+ /**
+ * Like above, but ignores any cells occupied by the item "ignoreView"
+ *
+ * @param cellXY The array that will contain the position of a vacant cell if such a cell
+ * can be found.
+ * @param spanX The horizontal span of the cell we want to find.
+ * @param spanY The vertical span of the cell we want to find.
+ * @param ignoreView The home screen item we should treat as not occupying any space
+ * @return
+ */
+ boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
+ return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, ignoreView);
+ }
+
+ /**
+ * Like above, but if intersectX and intersectY are not -1, then this method will try to
+ * return coordinates for rectangles that contain the cell [intersectX, intersectY]
+ *
+ * @param spanX The horizontal span of the cell we want to find.
+ * @param spanY The vertical span of the cell we want to find.
+ * @param ignoreView The home screen item we should treat as not occupying any space
+ * @param intersectX The X coordinate of the cell that we should try to overlap
+ * @param intersectX The Y coordinate of the cell that we should try to overlap
+ *
+ * @return True if a vacant cell of the specified dimension was found, false otherwise.
+ */
+ boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
+ int intersectX, int intersectY) {
+ return findCellForSpanThatIntersectsIgnoring(
+ cellXY, spanX, spanY, intersectX, intersectY, null);
+ }
+
+ /**
+ * The superset of the above two methods
+ */
+ boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
+ int intersectX, int intersectY, View ignoreView) {
+ // mark space take by ignoreView as available (method checks if ignoreView is null)
+ markCellsAsUnoccupiedForView(ignoreView);
+
+ boolean foundCell = false;
+ while (true) {
+ int startX = 0;
+ if (intersectX >= 0) {
+ startX = Math.max(startX, intersectX - (spanX - 1));
+ }
+ int endX = mCountX - (spanX - 1);
+ if (intersectX >= 0) {
+ endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
+ }
+ int startY = 0;
+ if (intersectY >= 0) {
+ startY = Math.max(startY, intersectY - (spanY - 1));
+ }
+ int endY = mCountY - (spanY - 1);
+ if (intersectY >= 0) {
+ endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
+ }
+
+ for (int y = startY; y < endY && !foundCell; y++) {
+ inner:
+ for (int x = startX; x < endX; x++) {
+ for (int i = 0; i < spanX; i++) {
+ for (int j = 0; j < spanY; j++) {
+ if (mOccupied[x + i][y + j]) {
+ // small optimization: we can skip to after the column we just found
+ // an occupied cell
+ x += i;
+ continue inner;
+ }
+ }
+ }
+ if (cellXY != null) {
+ cellXY[0] = x;
+ cellXY[1] = y;
+ }
+ foundCell = true;
+ break;
+ }
+ }
+ if (intersectX == -1 && intersectY == -1) {
+ break;
+ } else {
+ // if we failed to find anything, try again but without any requirements of
+ // intersecting
+ intersectX = -1;
+ intersectY = -1;
+ continue;
+ }
}
- mDragRect.setEmpty();
+
+ // re-mark space taken by ignoreView as occupied
+ markCellsAsOccupiedForView(ignoreView);
+ return foundCell;
+ }
+
+ /**
+ * Called when drag has left this CellLayout or has been completed (successfully or not)
+ */
+ void onDragExit() {
+ // This can actually be called when we aren't in a drag, e.g. when adding a new
+ // item to this layout via the customize drawer.
+ // Guard against that case.
+ if (mDragging) {
+ mDragging = false;
+
+ // Fade out the drag indicators
+ if (mCrosshairsAnimator != null) {
+ mCrosshairsAnimator.animateOut();
+ }
+ }
+
+ // Invalidate the drag data
+ mDragCell[0] = -1;
+ mDragCell[1] = -1;
+ mDragOutlineAnims[mDragOutlineCurrent].animateOut();
+ mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
+
+ setIsDragOverlapping(false);
+ }
+
+ /**
+ * Mark a child as having been dropped.
+ * At the beginning of the drag operation, the child may have been on another
+ * screen, but it is re-parented before this method is called.
+ *
+ * @param child The child that is being dropped
+ */
+ void onDropChild(View child, boolean animate) {
+ if (child != null) {
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.isDragging = false;
+ lp.dropped = true;
+ lp.animateDrop = animate;
+ child.setVisibility(animate ? View.INVISIBLE : View.VISIBLE);
+ child.requestLayout();
+ }
}
/**
* Start dragging the specified child
- *
+ *
* @param child The child that is being dragged
*/
void onDragChild(View child) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.isDragging = true;
- mDragRect.setEmpty();
}
-
+
/**
- * Drag a child over the specified position
- *
- * @param child The child that is being dropped
- * @param cellX The child's new x cell location
- * @param cellY The child's new y cell location
+ * A drag event has begun over this layout.
+ * It may have begun over this layout (in which case onDragChild is called first),
+ * or it may have begun on another layout.
*/
- void onDragOverChild(View child, int cellX, int cellY) {
- int[] cellXY = mCellXY;
- pointToCellRounded(cellX, cellY, cellXY);
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- cellToRect(cellXY[0], cellXY[1], lp.cellHSpan, lp.cellVSpan, mDragRect);
- invalidate();
+ void onDragEnter() {
+ if (!mDragging) {
+ // Fade in the drag indicators
+ if (mCrosshairsAnimator != null) {
+ mCrosshairsAnimator.animateIn();
+ }
+ }
+ mDragging = true;
}
-
+
/**
* Computes a bounding rectangle for a range of cells
- *
+ *
* @param cellX X coordinate of upper left corner expressed as a cell position
* @param cellY Y coordinate of upper left corner expressed as a cell position
- * @param cellHSpan Width in cells
+ * @param cellHSpan Width in cells
* @param cellVSpan Height in cells
- * @param dragRect Rectnagle into which to put the results
+ * @param resultRect Rect into which to put the results
*/
- public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) {
- final boolean portrait = mPortrait;
+ public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF resultRect) {
final int cellWidth = mCellWidth;
final int cellHeight = mCellHeight;
final int widthGap = mWidthGap;
final int heightGap = mHeightGap;
-
- final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding;
- final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding;
-
+
+ final int hStartPadding = getLeftPadding();
+ final int vStartPadding = getTopPadding();
+
int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
int x = hStartPadding + cellX * (cellWidth + widthGap);
int y = vStartPadding + cellY * (cellHeight + heightGap);
-
- dragRect.set(x, y, x + width, y + height);
+
+ resultRect.set(x, y, x + width, y + height);
}
-
+
/**
- * Computes the required horizontal and vertical cell spans to always
+ * Computes the required horizontal and vertical cell spans to always
* fit the given rectangle.
- *
+ *
* @param width Width in pixels
* @param height Height in pixels
+ * @param result An array of length 2 in which to store the result (may be null).
*/
- public int[] rectToCell(int width, int height) {
+ public int[] rectToCell(int width, int height, int[] result) {
+ return rectToCell(getResources(), width, height, result);
+ }
+
+ public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
// Always assume we're working with the smallest span to make sure we
// reserve enough space in both orientations.
- final Resources resources = getResources();
int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
int smallerSize = Math.min(actualWidth, actualHeight);
@@ -749,7 +1422,35 @@
int spanX = (width + smallerSize) / smallerSize;
int spanY = (height + smallerSize) / smallerSize;
- return new int[] { spanX, spanY };
+ if (result == null) {
+ return new int[] { spanX, spanY };
+ }
+ result[0] = spanX;
+ result[1] = spanY;
+ return result;
+ }
+
+ /**
+ * Calculate the grid spans needed to fit given item
+ */
+ public void calculateSpans(ItemInfo info) {
+ final int minWidth;
+ final int minHeight;
+
+ if (info instanceof LauncherAppWidgetInfo) {
+ minWidth = ((LauncherAppWidgetInfo) info).minWidth;
+ minHeight = ((LauncherAppWidgetInfo) info).minHeight;
+ } else if (info instanceof PendingAddWidgetInfo) {
+ minWidth = ((PendingAddWidgetInfo) info).minWidth;
+ minHeight = ((PendingAddWidgetInfo) info).minHeight;
+ } else {
+ // It's not a widget, so it must be 1x1
+ info.spanX = info.spanY = 1;
+ return;
+ }
+ int[] spans = rectToCell(minWidth, minHeight, null);
+ info.spanX = spans[0];
+ info.spanY = spans[1];
}
/**
@@ -758,18 +1459,12 @@
* @param vacant Holds the x and y coordinate of the vacant cell
* @param spanX Horizontal cell span.
* @param spanY Vertical cell span.
- *
+ *
* @return True if a vacant cell was found
*/
public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
- final boolean[][] occupied = mOccupied;
- findOccupiedCells(xCount, yCount, occupied, null);
-
- return findVacantCell(vacant, spanX, spanY, xCount, yCount, occupied);
+ return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
}
static boolean findVacantCell(int[] vacant, int spanX, int spanY,
@@ -796,43 +1491,36 @@
return false;
}
- boolean[] getOccupiedCells() {
- final boolean portrait = mPortrait;
- final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
- final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
- final boolean[][] occupied = mOccupied;
-
- findOccupiedCells(xCount, yCount, occupied, null);
-
- final boolean[] flat = new boolean[xCount * yCount];
- for (int y = 0; y < yCount; y++) {
- for (int x = 0; x < xCount; x++) {
- flat[y * xCount + x] = occupied[x][y];
+ private void clearOccupiedCells() {
+ for (int x = 0; x < mCountX; x++) {
+ for (int y = 0; y < mCountY; y++) {
+ mOccupied[x][y] = false;
}
}
-
- return flat;
}
- private void findOccupiedCells(int xCount, int yCount, boolean[][] occupied, View ignoreView) {
- for (int x = 0; x < xCount; x++) {
- for (int y = 0; y < yCount; y++) {
- occupied[x][y] = false;
- }
- }
+ public void onMove(View view, int newCellX, int newCellY) {
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ markCellsAsUnoccupiedForView(view);
+ markCellsForView(newCellX, newCellY, lp.cellHSpan, lp.cellVSpan, true);
+ }
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- if (child instanceof Folder || child.equals(ignoreView)) {
- continue;
- }
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ private void markCellsAsOccupiedForView(View view) {
+ if (view == null || view.getParent() != this) return;
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, true);
+ }
- for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan && x < xCount; x++) {
- for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan && y < yCount; y++) {
- occupied[x][y] = true;
- }
+ private void markCellsAsUnoccupiedForView(View view) {
+ if (view == null || view.getParent() != this) return;
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, false);
+ }
+
+ private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean value) {
+ for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
+ for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
+ mOccupied[x][y] = value;
}
}
}
@@ -852,6 +1540,17 @@
return new CellLayout.LayoutParams(p);
}
+ public static class CellLayoutAnimationController extends LayoutAnimationController {
+ public CellLayoutAnimationController(Animation animation, float delay) {
+ super(animation, delay);
+ }
+
+ @Override
+ protected long getDelayForView(View view) {
+ return (int) (Math.random() * 150);
+ }
+ }
+
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
/**
* Horizontal location of the item in the grid.
@@ -876,7 +1575,7 @@
*/
@ViewDebug.ExportedProperty
public int cellVSpan;
-
+
/**
* Is this item currently being dragged
*/
@@ -889,10 +1588,22 @@
@ViewDebug.ExportedProperty
int y;
- boolean regenerateId;
-
+ /**
+ * The old X coordinate of this item, relative to its current parent.
+ * Used to animate the item into its new position.
+ */
+ int oldX;
+
+ /**
+ * The old Y coordinate of this item, relative to its current parent.
+ * Used to animate the item into its new position.
+ */
+ int oldY;
+
boolean dropped;
+ boolean animateDrop;
+
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
cellHSpan = 1;
@@ -904,7 +1615,15 @@
cellHSpan = 1;
cellVSpan = 1;
}
-
+
+ public LayoutParams(LayoutParams source) {
+ super(source);
+ this.cellX = source.cellX;
+ this.cellY = source.cellY;
+ this.cellHSpan = source.cellHSpan;
+ this.cellVSpan = source.cellVSpan;
+ }
+
public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
this.cellX = cellX;
@@ -915,12 +1634,12 @@
public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
int hStartPadding, int vStartPadding) {
-
+
final int myCellHSpan = cellHSpan;
final int myCellVSpan = cellVSpan;
final int myCellX = cellX;
final int myCellY = cellY;
-
+
width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
leftMargin - rightMargin;
height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
@@ -929,172 +1648,42 @@
x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
}
+
+ public String toString() {
+ return "(" + this.cellX + ", " + this.cellY + ")";
+ }
}
+ // This class stores info for two purposes:
+ // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
+ // its spanX, spanY, and the screen it is on
+ // 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 {
- /**
- * See View.AttachInfo.InvalidateInfo for futher explanations about
- * the recycling mechanism. In this case, we recycle the vacant cells
- * instances because up to several hundreds can be instanciated when
- * the user long presses an empty cell.
- */
- static final class VacantCell {
- int cellX;
- int cellY;
- int spanX;
- int spanY;
-
- // We can create up to 523 vacant cells on a 4x4 grid, 100 seems
- // like a reasonable compromise given the size of a VacantCell and
- // the fact that the user is not likely to touch an empty 4x4 grid
- // very often
- private static final int POOL_LIMIT = 100;
- private static final Object sLock = new Object();
-
- private static int sAcquiredCount = 0;
- private static VacantCell sRoot;
-
- private VacantCell next;
-
- static VacantCell acquire() {
- synchronized (sLock) {
- if (sRoot == null) {
- return new VacantCell();
- }
-
- VacantCell info = sRoot;
- sRoot = info.next;
- sAcquiredCount--;
-
- return info;
- }
- }
-
- void release() {
- synchronized (sLock) {
- if (sAcquiredCount < POOL_LIMIT) {
- sAcquiredCount++;
- next = sRoot;
- sRoot = this;
- }
- }
- }
-
- @Override
- public String toString() {
- return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX +
- ", spanY=" + spanY + "]";
- }
- }
-
View cell;
- int cellX;
- int cellY;
+ int cellX = -1;
+ int cellY = -1;
int spanX;
int spanY;
int screen;
boolean valid;
- final ArrayList<VacantCell> vacantCells = new ArrayList<VacantCell>(VacantCell.POOL_LIMIT);
- int maxVacantSpanX;
- int maxVacantSpanXSpanY;
- int maxVacantSpanY;
- int maxVacantSpanYSpanX;
- final Rect current = new Rect();
-
- void clearVacantCells() {
- final ArrayList<VacantCell> list = vacantCells;
- final int count = list.size();
-
- for (int i = 0; i < count; i++) list.get(i).release();
-
- list.clear();
- }
-
- void findVacantCellsFromOccupied(boolean[] occupied, int xCount, int yCount) {
- if (cellX < 0 || cellY < 0) {
- maxVacantSpanX = maxVacantSpanXSpanY = Integer.MIN_VALUE;
- maxVacantSpanY = maxVacantSpanYSpanX = Integer.MIN_VALUE;
- clearVacantCells();
- return;
- }
-
- final boolean[][] unflattened = new boolean[xCount][yCount];
- for (int y = 0; y < yCount; y++) {
- for (int x = 0; x < xCount; x++) {
- unflattened[x][y] = occupied[y * xCount + x];
- }
- }
- CellLayout.findIntersectingVacantCells(this, cellX, cellY, xCount, yCount, unflattened);
- }
-
- /**
- * This method can be called only once! Calling #findVacantCellsFromOccupied will
- * restore the ability to call this method.
- *
- * Finds the upper-left coordinate of the first rectangle in the grid that can
- * hold a cell of the specified dimensions.
- *
- * @param cellXY The array that will contain the position of a vacant cell if such a cell
- * can be found.
- * @param spanX The horizontal span of the cell we want to find.
- * @param spanY The vertical span of the cell we want to find.
- *
- * @return True if a vacant cell of the specified dimension was found, false otherwise.
- */
- boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
- return findCellForSpan(cellXY, spanX, spanY, true);
- }
-
- boolean findCellForSpan(int[] cellXY, int spanX, int spanY, boolean clear) {
- final ArrayList<VacantCell> list = vacantCells;
- final int count = list.size();
-
- boolean found = false;
-
- if (this.spanX >= spanX && this.spanY >= spanY) {
- cellXY[0] = cellX;
- cellXY[1] = cellY;
- found = true;
- }
-
- // Look for an exact match first
- for (int i = 0; i < count; i++) {
- VacantCell cell = list.get(i);
- if (cell.spanX == spanX && cell.spanY == spanY) {
- cellXY[0] = cell.cellX;
- cellXY[1] = cell.cellY;
- found = true;
- break;
- }
- }
-
- // Look for the first cell large enough
- for (int i = 0; i < count; i++) {
- VacantCell cell = list.get(i);
- if (cell.spanX >= spanX && cell.spanY >= spanY) {
- cellXY[0] = cell.cellX;
- cellXY[1] = cell.cellY;
- found = true;
- break;
- }
- }
-
- if (clear) clearVacantCells();
-
- return found;
- }
-
@Override
public String toString() {
- return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + ", x=" + cellX +
- ", y=" + cellY + "]";
+ return "Cell[view=" + (cell == null ? "null" : cell.getClass())
+ + ", x=" + cellX + ", y=" + cellY + "]";
}
}
-
- public boolean lastDownOnOccupiedCell() {
- return mLastDownOnOccupiedCell;
- }
}
+// Custom interfaces used to listen to "visibility changed" events of *children* of Views. Avoided
+// using "onVisibilityChanged" in the names because there's a method of that name in framework
+// (which can only can be used to listen to ancestors' "visibility changed" events)
+interface VisibilityChangedBroadcaster {
+ public void setVisibilityChangedListener(VisibilityChangedListener listener);
+}
+interface VisibilityChangedListener {
+ public void receiveVisibilityChangedMessage(View v);
+}
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
new file mode 100644
index 0000000..c74e5f4
--- /dev/null
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+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.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.view.ActionMode;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.widget.Checkable;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+
+public class CustomizePagedView extends PagedViewWithDraggableItems
+ implements View.OnClickListener, DragSource, ActionMode.Callback {
+
+ public enum CustomizationType {
+ WidgetCustomization,
+ ShortcutCustomization,
+ WallpaperCustomization,
+ ApplicationCustomization
+ }
+
+ private static final String TAG = "CustomizeWorkspace";
+
+ private Launcher mLauncher;
+ private DragController mDragController;
+ private PackageManager mPackageManager;
+
+ private CustomizationType mCustomizationType;
+
+ // The layout used to emulate the workspace in resolve the cell dimensions of a widget
+ private PagedViewCellLayout mWorkspaceWidgetLayout;
+
+ // The mapping between the pages and the widgets that will be laid out on them
+ private ArrayList<ArrayList<AppWidgetProviderInfo>> mWidgetPages;
+
+ // The max dimensions for the ImageView we use for displaying a widget
+ private int mMaxWidgetWidth;
+
+ // The max number of widget cells to take a "page" of widgets
+ private int mMaxWidgetsCellHSpan;
+
+ // The size of the items on the wallpaper tab
+ private int mWallpaperCellHSpan;
+
+ // The max number of wallpaper cells to take a "page" of wallpaper items
+ private int mMaxWallpaperCellHSpan;
+
+ // The raw sources of data for each of the different tabs of the customization page
+ private List<AppWidgetProviderInfo> mWidgetList;
+ private List<ResolveInfo> mShortcutList;
+ private List<ResolveInfo> mWallpaperList;
+ private List<ApplicationInfo> mApps;
+
+ private static final int sMinWidgetCellHSpan = 2;
+ private static final int sMaxWidgetCellHSpan = 4;
+
+ private int mChoiceModeTitleText;
+
+ // The scale factor for widget previews inside the widget drawer
+ private static final float sScaleFactor = 0.75f;
+
+ private final Canvas mCanvas = new Canvas();
+ private final LayoutInflater mInflater;
+
+ private final float mTmpFloatPos[] = new float[2];
+ private final float ANIMATION_SCALE = 0.5f;
+ private final int ANIMATION_DURATION = 400;
+ private TimeInterpolator mQuintEaseOutInterpolator = new DecelerateInterpolator(2.5f);
+ private ScaleAlphaInterpolator mScaleAlphaInterpolator = new ScaleAlphaInterpolator();
+
+ public CustomizePagedView(Context context) {
+ this(context, null, 0);
+ }
+
+ public CustomizePagedView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public CustomizePagedView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a;
+ a = context.obtainStyledAttributes(attrs, R.styleable.CustomizePagedView, defStyle, 0);
+ mWallpaperCellHSpan = a.getInt(R.styleable.CustomizePagedView_wallpaperCellSpanX, 4);
+ mMaxWallpaperCellHSpan = a.getInt(R.styleable.CustomizePagedView_wallpaperCellCountX, 8);
+ mMaxWidgetsCellHSpan = a.getInt(R.styleable.CustomizePagedView_widgetCellCountX, 8);
+ a.recycle();
+ a = context.obtainStyledAttributes(attrs, R.styleable.PagedView, defStyle, 0);
+ mCellCountX = a.getInt(R.styleable.PagedView_cellCountX, 7);
+ mCellCountY = a.getInt(R.styleable.PagedView_cellCountY, 4);
+ a.recycle();
+
+ mCustomizationType = CustomizationType.WidgetCustomization;
+ mWidgetPages = new ArrayList<ArrayList<AppWidgetProviderInfo>>();
+ mWorkspaceWidgetLayout = new PagedViewCellLayout(context);
+ mInflater = LayoutInflater.from(context);
+
+ final Resources r = context.getResources();
+ setDragSlopeThreshold(
+ r.getInteger(R.integer.config_customizationDrawerDragSlopeThreshold) / 100.0f);
+
+ setVisibility(View.GONE);
+ setSoundEffectsEnabled(false);
+ setupWorkspaceLayout();
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+ mCenterPagesVertically = false;
+ }
+
+ public void setLauncher(Launcher launcher) {
+ Context context = getContext();
+ mLauncher = launcher;
+ mPackageManager = context.getPackageManager();
+ }
+
+ /**
+ * Sets the list of applications that launcher has loaded.
+ */
+ public void setApps(ArrayList<ApplicationInfo> list) {
+ mApps = list;
+ Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR);
+
+ // Update the widgets/shortcuts to reflect changes in the set of available apps
+ mPageViewIconCache.retainAllApps(list);
+ invalidatePageData();
+ }
+
+ /**
+ * Convenience function to add new items to the set of applications that were previously loaded.
+ * Called by both updateApps() and setApps().
+ */
+ private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+ // we add it in place, in alphabetical order
+ final int count = list.size();
+ for (int i = 0; i < count; ++i) {
+ final ApplicationInfo info = list.get(i);
+ final int index = Collections.binarySearch(mApps, info, LauncherModel.APP_NAME_COMPARATOR);
+ if (index < 0) {
+ mApps.add(-(index + 1), info);
+ }
+ }
+ }
+
+ /**
+ * Adds new applications to the loaded list, and notifies the paged view to update itself.
+ */
+ public void addApps(ArrayList<ApplicationInfo> list) {
+ addAppsWithoutInvalidate(list);
+
+ // Update the widgets/shortcuts to reflect changes in the set of available apps
+ invalidatePageData();
+ }
+
+ /**
+ * Convenience function to remove items to the set of applications that were previously loaded.
+ * Called by both updateApps() and removeApps().
+ */
+ private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+ // loop through all the apps and remove apps that have the same component
+ final int length = list.size();
+ for (int i = 0; i < length; ++i) {
+ final ApplicationInfo info = list.get(i);
+ int removeIndex = findAppByComponent(mApps, info);
+ if (removeIndex > -1) {
+ mApps.remove(removeIndex);
+ mPageViewIconCache.removeOutline(new PagedViewIconCache.Key(info));
+ }
+ }
+ }
+
+ /**
+ * Removes applications from the loaded list, and notifies the paged view to update itself.
+ */
+ public void removeApps(ArrayList<ApplicationInfo> list) {
+ removeAppsWithoutInvalidate(list);
+
+ // Update the widgets/shortcuts to reflect changes in the set of available apps
+ invalidatePageData();
+ }
+
+ /**
+ * Updates a set of applications from the loaded list, and notifies the paged view to update
+ * itself.
+ */
+ 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);
+
+ // Update the widgets/shortcuts to reflect changes in the set of available apps
+ invalidatePageData();
+ }
+
+ /**
+ * Convenience function to find matching ApplicationInfos for removal.
+ */
+ private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) {
+ ComponentName removeComponent = item.intent.getComponent();
+ final 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;
+ }
+
+ public void update() {
+ // get the list of widgets
+ mWidgetList = AppWidgetManager.getInstance(mLauncher).getInstalledProviders();
+ Collections.sort(mWidgetList, new Comparator<AppWidgetProviderInfo>() {
+ @Override
+ public int compare(AppWidgetProviderInfo object1, AppWidgetProviderInfo object2) {
+ return object1.label.compareTo(object2.label);
+ }
+ });
+
+ Comparator<ResolveInfo> resolveInfoComparator = new Comparator<ResolveInfo>() {
+ @Override
+ public int compare(ResolveInfo object1, ResolveInfo object2) {
+ return object1.loadLabel(mPackageManager).toString().compareTo(
+ object2.loadLabel(mPackageManager).toString());
+ }
+ };
+
+ // get the list of shortcuts
+ Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+ mShortcutList = mPackageManager.queryIntentActivities(shortcutsIntent, 0);
+ Collections.sort(mShortcutList, resolveInfoComparator);
+
+ // get the list of wallpapers
+ Intent wallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
+ mWallpaperList = mPackageManager.queryIntentActivities(wallpapersIntent,
+ PackageManager.GET_META_DATA);
+ Collections.sort(mWallpaperList, resolveInfoComparator);
+
+ ArrayList<ResolveInfo> retainShortcutList = new ArrayList<ResolveInfo>(mShortcutList);
+ retainShortcutList.addAll(mWallpaperList);
+ mPageViewIconCache.retainAllShortcuts(retainShortcutList);
+ mPageViewIconCache.retainAllAppWidgets(mWidgetList);
+ invalidatePageData();
+ }
+
+ public void setDragController(DragController dragger) {
+ mDragController = dragger;
+ }
+
+ public void setCustomizationFilter(CustomizationType filterType) {
+ cancelDragging();
+ mCustomizationType = filterType;
+ if (getChildCount() > 0) {
+ setCurrentPage(0);
+ updateCurrentPageScroll();
+ invalidatePageData();
+
+ // End the current choice mode so that we don't carry selections across tabs
+ endChoiceMode();
+ }
+ }
+
+ public CustomizationType getCustomizationFilter() {
+ return mCustomizationType;
+ }
+
+ @Override
+ public void onDropCompleted(View target, boolean success) {
+ resetCheckedGrandchildren();
+ mLauncher.getWorkspace().onDragStopped(success);
+ mLauncher.unlockScreenOrientation();
+ }
+
+ @Override
+ public void onDragViewVisible() {
+ }
+
+ class ScaleAlphaInterpolator implements Interpolator {
+ public float getInterpolation(float input) {
+ float pivot = 0.5f;
+ if (input < pivot) {
+ return 0;
+ } else {
+ return (input - pivot)/(1 - pivot);
+ }
+ }
+ }
+
+ private void animateItemOntoScreen(View dragView,
+ final CellLayout layout, final ItemInfo info) {
+ mTmpFloatPos[0] = layout.getWidth() / 2;
+ mTmpFloatPos[1] = layout.getHeight() / 2;
+ mLauncher.getWorkspace().mapPointFromChildToSelf(layout, mTmpFloatPos);
+
+ final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+ final View dragCopy = dragLayer.createDragView(dragView);
+ dragCopy.setAlpha(1.0f);
+
+ 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;
+ }
+ }
+
+ float toX = mTmpFloatPos[0] - dragView.getMeasuredWidth() / 2 + widthOffset;
+ float toY = mTmpFloatPos[1] - dragView.getMeasuredHeight() / 2 + heightOffset;
+
+ ObjectAnimator posAnim = ObjectAnimator.ofPropertyValuesHolder(dragCopy,
+ PropertyValuesHolder.ofFloat("x", toX),
+ PropertyValuesHolder.ofFloat("y", toY));
+ posAnim.setInterpolator(mQuintEaseOutInterpolator);
+ posAnim.setDuration(ANIMATION_DURATION);
+
+ posAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ dragLayer.removeView(dragCopy);
+ mLauncher.addExternalItemToScreen(info, layout);
+ post(new Runnable() {
+ public void run() {
+ layout.animateDrop();
+ }
+ });
+ }
+ });
+
+ ObjectAnimator scaleAlphaAnim = ObjectAnimator.ofPropertyValuesHolder(dragCopy,
+ PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f),
+ PropertyValuesHolder.ofFloat("scaleX", ANIMATION_SCALE),
+ PropertyValuesHolder.ofFloat("scaleY", ANIMATION_SCALE));
+ scaleAlphaAnim.setInterpolator(mScaleAlphaInterpolator);
+ scaleAlphaAnim.setDuration(ANIMATION_DURATION);
+
+ posAnim.start();
+ scaleAlphaAnim.start();
+ }
+
+ @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;
+
+ // On certain pages, we allow single tap to mark items as selected so that they can be
+ // dropped onto the mini workspaces
+ boolean enterChoiceMode = false;
+ switch (mCustomizationType) {
+ case WidgetCustomization:
+ mChoiceModeTitleText = R.string.cab_widget_selection_text;
+ enterChoiceMode = true;
+ break;
+ case ApplicationCustomization:
+ mChoiceModeTitleText = R.string.cab_app_selection_text;
+ enterChoiceMode = true;
+ break;
+ case ShortcutCustomization:
+ mChoiceModeTitleText = R.string.cab_shortcut_selection_text;
+ enterChoiceMode = true;
+ break;
+ default:
+ break;
+ }
+
+ if (enterChoiceMode) {
+ final ItemInfo itemInfo = (ItemInfo) v.getTag();
+
+ Workspace w = mLauncher.getWorkspace();
+ int currentWorkspaceScreen = mLauncher.getCurrentWorkspaceScreen();
+ final CellLayout cl = (CellLayout)w.getChildAt(currentWorkspaceScreen);
+ final View dragView = getDragView(v);
+
+ animateClickFeedback(v, new Runnable() {
+ @Override
+ public void run() {
+ cl.calculateSpans(itemInfo);
+ if (cl.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY)) {
+ animateItemOntoScreen(dragView, cl, itemInfo);
+ } else {
+ mLauncher.showOutOfSpaceMessage();
+ }
+ }
+ });
+ return;
+ }
+
+ // Otherwise, we just handle the single click here
+ switch (mCustomizationType) {
+ case WallpaperCustomization:
+ // animate some feedback to the long press
+ final View clickView = v;
+ animateClickFeedback(v, new Runnable() {
+ @Override
+ public void run() {
+ // add the shortcut
+ ResolveInfo info = (ResolveInfo) clickView.getTag();
+ Intent createWallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
+ ComponentName name = new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name);
+ createWallpapersIntent.setComponent(name);
+ mLauncher.processWallpaper(createWallpapersIntent);
+ }
+ });
+ break;
+ default:
+ break;
+ }
+ }
+
+ Bitmap drawableToBitmap(Drawable d, View v) {
+ Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ c.translate((v.getWidth() - d.getIntrinsicWidth()) / 2, v.getPaddingTop());
+ d.draw(c);
+ return b;
+ }
+
+ private View getDragView(View v) {
+ return (mCustomizationType == CustomizationType.WidgetCustomization) ?
+ v.findViewById(R.id.widget_preview) : v;
+ }
+
+ protected boolean beginDragging(View v) {
+ if (!v.isInTouchMode()) return false;
+ if (!super.beginDragging(v)) return false;
+
+ // End the current choice mode before we start dragging anything
+ if (isChoiceMode(CHOICE_MODE_SINGLE)) {
+ endChoiceMode();
+ }
+ boolean result = false;
+ mLauncher.lockScreenOrientation();
+ switch (mCustomizationType) {
+ case WidgetCustomization: {
+ if (v instanceof PagedViewWidget) {
+ // Get the widget preview as the drag representation
+ final LinearLayout l = (LinearLayout) v;
+ final ImageView i = (ImageView) l.findViewById(R.id.widget_preview);
+ final Drawable icon = i.getDrawable();
+ Bitmap b = drawableToBitmap(icon, i);
+ PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) v.getTag();
+
+ int[] spanXY = CellLayout.rectToCell(
+ getResources(), createWidgetInfo.minWidth, createWidgetInfo.minHeight, null);
+ createWidgetInfo.spanX = spanXY[0];
+ createWidgetInfo.spanY = spanXY[1];
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(spanXY[0], spanXY[1], b);
+ mDragController.startDrag(
+ i, b, this, createWidgetInfo, DragController.DRAG_ACTION_COPY, null);
+ b.recycle();
+ result = true;
+ }
+ break;
+ }
+ case ShortcutCustomization: {
+ if (v instanceof PagedViewIcon) {
+ // get icon (top compound drawable, index is 1)
+ final TextView tv = (TextView) v;
+ final Drawable icon = tv.getCompoundDrawables()[1];
+ Bitmap b = drawableToBitmap(icon, tv);
+ PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
+
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
+ mDragController.startDrag(v, b, this, createItemInfo, DragController.DRAG_ACTION_COPY,
+ null);
+ b.recycle();
+ result = true;
+ }
+ break;
+ }
+ case ApplicationCustomization: {
+ if (v instanceof PagedViewIcon) {
+ // Pick up the application for dropping
+ // get icon (top compound drawable, index is 1)
+ final TextView tv = (TextView) v;
+ final Drawable icon = tv.getCompoundDrawables()[1];
+ Bitmap b = drawableToBitmap(icon, tv);
+ ApplicationInfo app = (ApplicationInfo) v.getTag();
+ app = new ApplicationInfo(app);
+
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
+ mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, null);
+ b.recycle();
+ result = true;
+ }
+ break;
+ }
+ }
+
+ // 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 (result && (v instanceof Checkable)) {
+ // In preparation for drag, we always reset the checked grand children regardless of
+ // what choice mode we are in
+ resetCheckedGrandchildren();
+
+ // Toggle the selection on the dragged app
+ Checkable checkable = (Checkable) v;
+
+ // Note: we toggle the checkable state to actually cause an alpha fade for the duration
+ // of the drag of the item. (The fade-in will occur when all checked states are
+ // disabled when dragging ends)
+ checkable.toggle();
+ }
+
+ return result;
+ }
+
+ /**
+ * Pre-processes the layout of the different widget pages.
+ * @return the number of pages of widgets that we have
+ */
+ private int relayoutWidgets() {
+ if (mWidgetList.isEmpty()) return 0;
+
+ // create a new page for the first set of widgets
+ ArrayList<AppWidgetProviderInfo> newPage = new ArrayList<AppWidgetProviderInfo>();
+ mWidgetPages.clear();
+ mWidgetPages.add(newPage);
+
+ // do this until we have no more widgets to lay out
+ final int maxNumCellsPerRow = mMaxWidgetsCellHSpan;
+ final int widgetCount = mWidgetList.size();
+ int numCellsInRow = 0;
+ for (int i = 0; i < widgetCount; ++i) {
+ final AppWidgetProviderInfo info = mWidgetList.get(i);
+
+ // determine the size of the current widget
+ int cellSpanX = Math.max(sMinWidgetCellHSpan, Math.min(sMaxWidgetCellHSpan,
+ mWorkspaceWidgetLayout.estimateCellHSpan(info.minWidth)));
+
+ // create a new page if necessary
+ if ((numCellsInRow + cellSpanX) > maxNumCellsPerRow) {
+ numCellsInRow = 0;
+ newPage = new ArrayList<AppWidgetProviderInfo>();
+ mWidgetPages.add(newPage);
+ }
+
+ // add the item to the current page
+ newPage.add(info);
+ numCellsInRow += cellSpanX;
+ }
+
+ return mWidgetPages.size();
+ }
+
+ /**
+ * Helper function to draw a drawable to the specified canvas with the specified bounds.
+ */
+ private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h) {
+ if (bitmap != null) mCanvas.setBitmap(bitmap);
+ mCanvas.save();
+ d.setBounds(x, y, x+w, y+h);
+ d.draw(mCanvas);
+ mCanvas.restore();
+ }
+
+ /*
+ * 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(ComponentName component, ResolveInfo ri) {
+ ActivityInfo activityInfo = ri.activityInfo;
+ XmlResourceParser parser = null;
+ try {
+ parser = activityInfo.loadXmlMetaData(mPackageManager,
+ WallpaperManager.WALLPAPER_PREVIEW_META_DATA);
+ if (parser == null) {
+ Slog.w(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(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(TAG, "XML parsing failed for wallpaper provider '" + component + '\'', e);
+ return null;
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ /**
+ * This method will extract the preview image specified by the wallpaper source provider (if it
+ * exists) otherwise, it will try to generate a default image preview.
+ */
+ private FastBitmapDrawable getWallpaperPreview(ResolveInfo info) {
+ // To be implemented later: resolving the up-to-date wallpaper thumbnail
+
+ final int minDim = mWorkspaceWidgetLayout.estimateCellWidth(1);
+ final int dim = mWorkspaceWidgetLayout.estimateCellWidth(mWallpaperCellHSpan);
+ Resources resources = mLauncher.getResources();
+
+ // Create a new bitmap to hold the widget preview
+ int width = (int) (dim * sScaleFactor);
+ int height = (int) (dim * sScaleFactor);
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
+
+ Drawable background = parseWallpaperPreviewXml(
+ new ComponentName(info.activityInfo.packageName, info.activityInfo.name), info);
+ boolean foundCustomDrawable = background != null;
+
+ if (!foundCustomDrawable) {
+ background = resources.getDrawable(R.drawable.default_widget_preview);
+ }
+
+ renderDrawableToBitmap(background, bitmap, 0, 0, width, height);
+
+ // If we don't have a custom icon, we use the app icon on the default background
+ if (!foundCustomDrawable) {
+ try {
+ final IconCache iconCache =
+ ((LauncherApplication) mLauncher.getApplication()).getIconCache();
+ Drawable icon = new FastBitmapDrawable(Utilities.createIconBitmap(
+ iconCache.getFullResIcon(info, mPackageManager), mContext));
+
+ final int iconSize = minDim / 2;
+ final int offset = iconSize / 4;
+ renderDrawableToBitmap(icon, null, offset, offset, iconSize, iconSize);
+ } catch (Resources.NotFoundException e) {
+ // if we can't find the icon, then just don't draw it
+ }
+ }
+
+ FastBitmapDrawable drawable = new FastBitmapDrawable(bitmap);
+ drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+ return drawable;
+ }
+
+ /**
+ * This method will extract the preview image specified by the widget developer (if it exists),
+ * otherwise, it will try to generate a default image preview with the widget's package icon.
+ * @return the drawable that will be used and sized in the ImageView to represent the widget
+ */
+ private FastBitmapDrawable getWidgetPreview(AppWidgetProviderInfo info) {
+ final PackageManager packageManager = mPackageManager;
+ String packageName = info.provider.getPackageName();
+ Drawable drawable = null;
+ FastBitmapDrawable newDrawable = null;
+ if (info.previewImage != 0) {
+ drawable = packageManager.getDrawable(packageName, info.previewImage, null);
+ if (drawable == null) {
+ Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+ + " for provider: " + info.provider);
+ }
+ }
+
+ // If we don't have a preview image, create a default one
+ final int minDim = mWorkspaceWidgetLayout.estimateCellWidth(1);
+ final int maxDim = mWorkspaceWidgetLayout.estimateCellWidth(3);
+ if (drawable == null) {
+ Resources resources = mLauncher.getResources();
+
+ // Create a new bitmap to hold the widget preview
+ int width = (int) (Math.max(minDim, Math.min(maxDim, info.minWidth)) * sScaleFactor);
+ int height = (int) (Math.max(minDim, Math.min(maxDim, info.minHeight)) * sScaleFactor);
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
+ final Drawable background = resources.getDrawable(R.drawable.default_widget_preview);
+ renderDrawableToBitmap(background, bitmap, 0, 0, width, height);
+
+ // Draw the icon flush left
+ try {
+ Drawable icon = null;
+ if (info.icon > 0) {
+ icon = packageManager.getDrawable(packageName, info.icon, null);
+ }
+ if (icon == null) {
+ icon = resources.getDrawable(R.drawable.ic_launcher_application);
+ }
+
+ final int iconSize = minDim / 2;
+ final int offset = iconSize / 4;
+ renderDrawableToBitmap(icon, null, offset, offset, iconSize, iconSize);
+ } catch (Resources.NotFoundException e) {
+ // if we can't find the icon, then just don't draw it
+ }
+
+ newDrawable = new FastBitmapDrawable(bitmap);
+ } else {
+ // Scale down the preview if necessary
+ final float imageWidth = drawable.getIntrinsicWidth();
+ final float imageHeight = drawable.getIntrinsicHeight();
+ final float aspect = (float) imageWidth / imageHeight;
+ final int scaledWidth =
+ (int) (Math.max(minDim, Math.min(maxDim, imageWidth)) * sScaleFactor);
+ final int scaledHeight =
+ (int) (Math.max(minDim, Math.min(maxDim, imageHeight)) * sScaleFactor);
+ int width;
+ int height;
+ if (aspect >= 1.0f) {
+ width = scaledWidth;
+ height = (int) (((float) scaledWidth / imageWidth) * imageHeight);
+ } else {
+ height = scaledHeight;
+ width = (int) (((float) scaledHeight / imageHeight) * imageWidth);
+ }
+
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
+ renderDrawableToBitmap(drawable, bitmap, 0, 0, width, height);
+
+ newDrawable = new FastBitmapDrawable(bitmap);
+ }
+ newDrawable.setBounds(0, 0, newDrawable.getIntrinsicWidth(),
+ newDrawable.getIntrinsicHeight());
+ return newDrawable;
+ }
+
+ private void setupPage(PagedViewCellLayout layout) {
+ layout.setCellCount(mCellCountX, mCellCountY);
+ layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, mPageLayoutPaddingRight,
+ mPageLayoutPaddingBottom);
+ layout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap);
+ }
+
+ private void setupWorkspaceLayout() {
+ mWorkspaceWidgetLayout.setCellCount(mCellCountX, mCellCountY);
+ mWorkspaceWidgetLayout.setPadding(20, 10, 20, 0);
+
+ mMaxWidgetWidth = mWorkspaceWidgetLayout.estimateCellWidth(sMaxWidgetCellHSpan);
+ }
+
+ private void syncWidgetPages() {
+ if (mWidgetList == null) return;
+
+ // we need to repopulate with the LinearLayout layout for the widget pages
+ removeAllViews();
+ int numPages = relayoutWidgets();
+ for (int i = 0; i < numPages; ++i) {
+ LinearLayout layout = new PagedViewExtendedLayout(getContext());
+ layout.setGravity(Gravity.CENTER_HORIZONTAL);
+ layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
+ mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
+
+ addView(layout, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.MATCH_PARENT));
+ }
+ }
+
+ private void syncWidgetPageItems(int page) {
+ // ensure that we have the right number of items on the pages
+ LinearLayout layout = (LinearLayout) getChildAt(page);
+ final ArrayList<AppWidgetProviderInfo> list = mWidgetPages.get(page);
+ final int count = list.size();
+ final int numPages = getPageCount();
+ layout.removeAllViews();
+ for (int i = 0; i < count; ++i) {
+ final AppWidgetProviderInfo info = (AppWidgetProviderInfo) list.get(i);
+ final PendingAddWidgetInfo createItemInfo = new PendingAddWidgetInfo(info, null, null);
+ final int[] cellSpans = CellLayout.rectToCell(getResources(), info.minWidth,
+ info.minHeight, null);
+ final FastBitmapDrawable icon = getWidgetPreview(info);
+
+ PagedViewWidget l = (PagedViewWidget) mInflater.inflate(
+ R.layout.customize_paged_view_widget, layout, false);
+ l.applyFromAppWidgetProviderInfo(info, icon, mMaxWidgetWidth, cellSpans,
+ mPageViewIconCache, (numPages > 1));
+ l.setTag(createItemInfo);
+ l.setOnClickListener(this);
+ l.setOnTouchListener(this);
+ l.setOnLongClickListener(this);
+
+ layout.addView(l);
+ }
+ }
+
+ private void syncWallpaperPages() {
+ if (mWallpaperList == null) return;
+
+ // We need to repopulate the LinearLayout for the wallpaper pages
+ removeAllViews();
+ int numPages = (int) Math.ceil((float) (mWallpaperList.size() * mWallpaperCellHSpan) /
+ mMaxWallpaperCellHSpan);
+ for (int i = 0; i < numPages; ++i) {
+ LinearLayout layout = new PagedViewExtendedLayout(getContext());
+ layout.setGravity(Gravity.CENTER_HORIZONTAL);
+ layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
+ mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
+
+ addView(layout, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.MATCH_PARENT));
+ }
+ }
+
+ private void syncWallpaperPageItems(int page) {
+ // Load the items on to the pages
+ LinearLayout layout = (LinearLayout) getChildAt(page);
+ layout.removeAllViews();
+ final int count = mWallpaperList.size();
+ final int numPages = getPageCount();
+ final int numItemsPerPage = mMaxWallpaperCellHSpan / mWallpaperCellHSpan;
+ final int startIndex = page * numItemsPerPage;
+ final int endIndex = Math.min(count, startIndex + numItemsPerPage);
+ for (int i = startIndex; i < endIndex; ++i) {
+ final ResolveInfo info = mWallpaperList.get(i);
+ final FastBitmapDrawable icon = getWallpaperPreview(info);
+
+ PagedViewWidget l = (PagedViewWidget) mInflater.inflate(
+ R.layout.customize_paged_view_wallpaper, layout, false);
+ l.applyFromWallpaperInfo(info, mPackageManager, icon, mMaxWidgetWidth,
+ mPageViewIconCache, (numPages > 1));
+ l.setTag(info);
+ l.setOnClickListener(this);
+
+ layout.addView(l);
+ }
+ }
+
+ private void syncListPages(List<ResolveInfo> list) {
+ // we need to repopulate with PagedViewCellLayouts
+ removeAllViews();
+
+ // ensure that we have the right number of pages
+ int numPages = (int) Math.ceil((float) list.size() / (mCellCountX * mCellCountY));
+ for (int i = 0; i < numPages; ++i) {
+ PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
+ setupPage(layout);
+ addView(layout);
+ }
+ }
+
+ private void syncListPageItems(int page, List<ResolveInfo> list) {
+ // ensure that we have the right number of items on the pages
+ final int numPages = getPageCount();
+ final int numCells = mCellCountX * mCellCountY;
+ final int startIndex = page * numCells;
+ final int endIndex = Math.min(startIndex + numCells, list.size());
+ final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
+ // TODO: we can optimize by just re-applying to existing views
+ layout.removeAllViews();
+ for (int i = startIndex; i < endIndex; ++i) {
+ ResolveInfo info = list.get(i);
+ PendingAddItemInfo createItemInfo = new PendingAddItemInfo();
+
+ PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
+ R.layout.customize_paged_view_item, layout, false);
+ icon.applyFromResolveInfo(info, mPackageManager, mPageViewIconCache,
+ ((LauncherApplication) mLauncher.getApplication()).getIconCache(),
+ (numPages > 1));
+ switch (mCustomizationType) {
+ case WallpaperCustomization:
+ icon.setOnClickListener(this);
+ break;
+ case ShortcutCustomization:
+ createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+ createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name);
+ icon.setTag(createItemInfo);
+ icon.setOnClickListener(this);
+ icon.setOnTouchListener(this);
+ icon.setOnLongClickListener(this);
+ break;
+ default:
+ break;
+ }
+
+ final int index = i - startIndex;
+ final int x = index % mCellCountX;
+ final int y = index / mCellCountX;
+ setupPage(layout);
+ layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
+ }
+ }
+
+ private void syncAppPages() {
+ if (mApps == null) return;
+
+ // We need to repopulate with PagedViewCellLayouts
+ removeAllViews();
+
+ // Ensure that we have the right number of pages
+ int numPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
+ for (int i = 0; i < numPages; ++i) {
+ PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
+ setupPage(layout);
+ addView(layout);
+ }
+ }
+
+ private void syncAppPageItems(int page) {
+ if (mApps == null) return;
+
+ // ensure that we have the right number of items on the pages
+ final int numPages = getPageCount();
+ final int numCells = mCellCountX * mCellCountY;
+ final int startIndex = page * numCells;
+ final int endIndex = Math.min(startIndex + numCells, mApps.size());
+ final PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
+ // TODO: we can optimize by just re-applying to existing views
+ layout.removeAllViews();
+ for (int i = startIndex; i < endIndex; ++i) {
+ final ApplicationInfo info = mApps.get(i);
+ PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
+ R.layout.all_apps_paged_view_application, layout, false);
+ icon.applyFromApplicationInfo(info, mPageViewIconCache, true, (numPages > 1));
+ icon.setOnClickListener(this);
+ icon.setOnTouchListener(this);
+ icon.setOnLongClickListener(this);
+
+ final int index = i - startIndex;
+ final int x = index % mCellCountX;
+ final int y = index / mCellCountX;
+ setupPage(layout);
+ layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
+ }
+ }
+
+ @Override
+ public void syncPages() {
+ boolean centerPagedViewCellLayouts = false;
+ switch (mCustomizationType) {
+ case WidgetCustomization:
+ syncWidgetPages();
+ break;
+ case ShortcutCustomization:
+ syncListPages(mShortcutList);
+ centerPagedViewCellLayouts = true;
+ break;
+ case WallpaperCustomization:
+ syncWallpaperPages();
+ break;
+ case ApplicationCustomization:
+ syncAppPages();
+ centerPagedViewCellLayouts = false;
+ break;
+ default:
+ removeAllViews();
+ setCurrentPage(0);
+ break;
+ }
+
+ // only try and center the page if there is one page
+ final int childCount = getChildCount();
+ if (centerPagedViewCellLayouts) {
+ if (childCount == 1) {
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(0);
+ layout.enableCenteredContent(true);
+ } else {
+ for (int i = 0; i < childCount; ++i) {
+ PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(i);
+ layout.enableCenteredContent(false);
+ }
+ }
+ }
+
+ // bound the current page
+ setCurrentPage(Math.max(0, Math.min(childCount - 1, getCurrentPage())));
+ }
+
+ @Override
+ public void syncPageItems(int page) {
+ switch (mCustomizationType) {
+ case WidgetCustomization:
+ syncWidgetPageItems(page);
+ break;
+ case ShortcutCustomization:
+ syncListPageItems(page, mShortcutList);
+ break;
+ case WallpaperCustomization:
+ syncWallpaperPageItems(page);
+ break;
+ case ApplicationCustomization:
+ syncAppPageItems(page);
+ break;
+ }
+ }
+
+ @Override
+ protected int getAssociatedLowerPageBound(int page) {
+ return 0;
+ }
+ @Override
+ protected int getAssociatedUpperPageBound(int page) {
+ return getChildCount();
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ mode.setTitle(mChoiceModeTitleText);
+ return true;
+ }
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ endChoiceMode();
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ return false;
+ }
+}
diff --git a/src/com/android/launcher2/DeferredHandler.java b/src/com/android/launcher2/DeferredHandler.java
index 7801642..930da56 100644
--- a/src/com/android/launcher2/DeferredHandler.java
+++ b/src/com/android/launcher2/DeferredHandler.java
@@ -16,13 +16,12 @@
package com.android.launcher2;
+import java.util.LinkedList;
+
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
-import android.util.Log;
-
-import java.util.LinkedList;
/**
* Queue of things to run on a looper thread. Items posted with {@link #post} will not
@@ -32,7 +31,7 @@
* This class is fifo.
*/
public class DeferredHandler {
- private LinkedList<Runnable> mQueue = new LinkedList();
+ private LinkedList<Runnable> mQueue = new LinkedList<Runnable>();
private MessageQueue mMessageQueue = Looper.myQueue();
private Impl mHandler = new Impl();
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index 4e8b204..98d2b83 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -16,34 +16,31 @@
package com.android.launcher2;
-import android.widget.ImageView;
+import com.android.launcher.R;
+
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.animation.TranslateAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AlphaAnimation;
import android.graphics.RectF;
import android.graphics.drawable.TransitionDrawable;
+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 ImageView implements DropTarget, DragController.DragListener {
+public class DeleteZone extends IconDropTarget {
private static final int ORIENTATION_HORIZONTAL = 1;
private static final int TRANSITION_DURATION = 250;
private static final int ANIMATION_DURATION = 200;
-
- private final int[] mLocation = new int[2];
-
- private Launcher mLauncher;
- private boolean mTrashMode;
+ private static final int XLARGE_TRANSITION_DURATION = 150;
+ private static final int XLARGE_ANIMATION_DURATION = 200;
+ private static final int LEFT_DRAWABLE = 0;
private AnimationSet mInAnimation;
private AnimationSet mOutAnimation;
@@ -53,10 +50,11 @@
private int mOrientation;
private DragController mDragController;
- private final RectF mRegion = new RectF();
+ private final RectF mRegionF = new RectF();
+ private final Rect mRegion = new Rect();
private TransitionDrawable mTransition;
- private View mHandle;
- private final Paint mTrashPaint = new Paint();
+ private int mTextColor;
+ private int mDragTextColor;
public DeleteZone(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -66,48 +64,64 @@
super(context, attrs, defStyle);
final int srcColor = context.getResources().getColor(R.color.delete_color_filter);
- mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
+ mHoverPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeleteZone, defStyle, 0);
mOrientation = a.getInt(R.styleable.DeleteZone_direction, ORIENTATION_HORIZONTAL);
a.recycle();
+
+ if (LauncherApplication.isScreenXLarge()) {
+ int tb = getResources().getDimensionPixelSize(
+ R.dimen.delete_zone_vertical_drag_padding);
+ int lr = getResources().getDimensionPixelSize(
+ R.dimen.delete_zone_horizontal_drag_padding);
+ setDragPadding(tb, lr, tb, lr);
+ }
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mTransition = (TransitionDrawable) getDrawable();
+ mTransition = (TransitionDrawable) getCompoundDrawables()[LEFT_DRAWABLE];
+ if (LauncherApplication.isScreenXLarge()) {
+ mTransition.setCrossFadeEnabled(false);
+ }
+
+ Resources r = getResources();
+ mTextColor = r.getColor(R.color.workspace_all_apps_and_delete_zone_text_color);
+ mDragTextColor = r.getColor(R.color.workspace_delete_zone_drag_text_color);
}
public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
return true;
}
-
- public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo, Rect recycle) {
- return null;
- }
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
+ if (!mDragAndDropEnabled) return;
+
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()) {
+ mLauncher.startApplicationUninstallActivity((ApplicationInfo) item);
+ }
+
if (item.container == -1) return;
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
if (item instanceof LauncherAppWidgetInfo) {
mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
}
- } else {
- if (source instanceof UserFolder) {
- final UserFolder userFolder = (UserFolder) source;
- final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo();
- // Item must be a ShortcutInfo otherwise it couldn't have been in the folder
- // in the first place.
- userFolderInfo.remove((ShortcutInfo)item);
- }
+ } else if (source instanceof UserFolder) {
+ final UserFolder userFolder = (UserFolder) source;
+ final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo();
+ // Item must be a ShortcutInfo otherwise it couldn't have been in the folder
+ // in the first place.
+ userFolderInfo.remove((ShortcutInfo)item);
}
+
if (item instanceof UserFolderInfo) {
final UserFolderInfo userFolderInfo = (UserFolderInfo)item;
LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo);
@@ -116,7 +130,6 @@
final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
if (appWidgetHost != null) {
- final int appWidgetId = launcherAppWidgetInfo.appWidgetId;
// Deleting an app widget ID is a void call but writes to disk before returning
// to the caller...
new Thread("deleteAppWidgetId") {
@@ -126,106 +139,141 @@
}.start();
}
}
+
LauncherModel.deleteItemFromDatabase(mLauncher, item);
}
public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
- mTransition.reverseTransition(TRANSITION_DURATION);
- dragView.setPaint(mTrashPaint);
- }
-
- public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
+ if (mDragAndDropEnabled) {
+ mTransition.reverseTransition(getTransitionAnimationDuration());
+ setTextColor(mDragTextColor);
+ super.onDragEnter(source, x, y, xOffset, yOffset, dragView, dragInfo);
+ }
}
public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
- mTransition.reverseTransition(TRANSITION_DURATION);
- dragView.setPaint(null);
+ if (mDragAndDropEnabled) {
+ mTransition.reverseTransition(getTransitionAnimationDuration());
+ setTextColor(mTextColor);
+ super.onDragExit(source, x, y, xOffset, yOffset, dragView, dragInfo);
+ }
}
public void onDragStart(DragSource source, Object info, int dragAction) {
final ItemInfo item = (ItemInfo) info;
- if (item != null) {
- mTrashMode = true;
- createAnimations();
- final int[] location = mLocation;
- getLocationOnScreen(location);
- mRegion.set(location[0], location[1], location[0] + mRight - mLeft,
- location[1] + mBottom - mTop);
- mDragController.setDeleteRegion(mRegion);
+ if (item != null && mDragAndDropEnabled) {
+ mActive = true;
+ getHitRect(mRegion);
+ mRegionF.set(mRegion);
+
+ if (LauncherApplication.isScreenXLarge()) {
+ // 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();
+ mRegionF.right = mLauncher.getWorkspace().getRight();
+ }
+
+ mDragController.setDeleteRegion(mRegionF);
+
+ // Make sure the icon is set to the default drawable, not the hover drawable
mTransition.resetTransition();
+
+ createAnimations();
startAnimation(mInAnimation);
- mHandle.startAnimation(mHandleOutAnimation);
+ if (mOverlappingViews != null) {
+ for (View view : mOverlappingViews) {
+ view.startAnimation(mHandleOutAnimation);
+ }
+ }
setVisibility(VISIBLE);
}
}
public void onDragEnd() {
- if (mTrashMode) {
- mTrashMode = false;
+ if (mActive && mDragAndDropEnabled) {
+ mActive = false;
mDragController.setDeleteRegion(null);
- startAnimation(mOutAnimation);
- mHandle.startAnimation(mHandleInAnimation);
+
+ if (mOutAnimation != null) startAnimation(mOutAnimation);
+ if (mHandleInAnimation != null && mOverlappingViews != null) {
+ for (View view : mOverlappingViews) {
+ view.startAnimation(mHandleInAnimation);
+ }
+ }
setVisibility(GONE);
}
}
private void createAnimations() {
- if (mInAnimation == null) {
- mInAnimation = new FastAnimationSet();
- final AnimationSet animationSet = mInAnimation;
- animationSet.setInterpolator(new AccelerateInterpolator());
- animationSet.addAnimation(new AlphaAnimation(0.0f, 1.0f));
- 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));
- } 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));
- }
- animationSet.setDuration(ANIMATION_DURATION);
- }
+ int duration = getAnimationDuration();
if (mHandleInAnimation == null) {
mHandleInAnimation = new AlphaAnimation(0.0f, 1.0f);
- mHandleInAnimation.setDuration(ANIMATION_DURATION);
+ mHandleInAnimation.setDuration(duration);
}
- if (mOutAnimation == null) {
- mOutAnimation = new FastAnimationSet();
- final AnimationSet animationSet = mOutAnimation;
- animationSet.setInterpolator(new AccelerateInterpolator());
- animationSet.addAnimation(new AlphaAnimation(1.0f, 0.0f));
- 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));
+
+ 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));
+ 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));
+ } 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));
+ }
+ animationSet.setDuration(duration);
} 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));
+ mInAnimation.addAnimation(mHandleInAnimation);
}
- animationSet.setDuration(ANIMATION_DURATION);
}
+
if (mHandleOutAnimation == null) {
mHandleOutAnimation = new AlphaAnimation(1.0f, 0.0f);
mHandleOutAnimation.setFillAfter(true);
- mHandleOutAnimation.setDuration(ANIMATION_DURATION);
+ mHandleOutAnimation.setDuration(duration);
}
- }
- void setLauncher(Launcher launcher) {
- mLauncher = launcher;
+ 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));
+ 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));
+ } 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));
+ }
+ animationSet.setDuration(duration);
+ } else {
+ mOutAnimation.addAnimation(mHandleOutAnimation);
+ }
+ }
}
void setDragController(DragController dragController) {
mDragController = dragController;
}
- void setHandle(View view) {
- mHandle = view;
+ private int getTransitionAnimationDuration() {
+ return LauncherApplication.isScreenXLarge() ?
+ XLARGE_TRANSITION_DURATION : TRANSITION_DURATION;
+ }
+
+ private int getAnimationDuration() {
+ return LauncherApplication.isScreenXLarge() ?
+ XLARGE_ANIMATION_DURATION : ANIMATION_DURATION;
}
private static class FastTranslateAnimation extends TranslateAnimation {
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index b453061..45b359d 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -16,23 +16,24 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.os.IBinder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.View;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
-import java.util.ArrayList;
-
import com.android.launcher.R;
/**
@@ -56,8 +57,9 @@
private static final int SCROLL_OUTSIDE_ZONE = 0;
private static final int SCROLL_WAITING_IN_ZONE = 1;
- private static final int SCROLL_LEFT = 0;
- private static final int SCROLL_RIGHT = 1;
+ static final int SCROLL_NONE = -1;
+ static final int SCROLL_LEFT = 0;
+ static final int SCROLL_RIGHT = 1;
private Context mContext;
private Handler mHandler;
@@ -105,7 +107,7 @@
/** Who can receive drop events */
private ArrayList<DropTarget> mDropTargets = new ArrayList<DropTarget>();
- private DragListener mListener;
+ private ArrayList<DragListener> mListeners = new ArrayList<DragListener>();
/** The window token used as the parent for the DragView. */
private IBinder mWindowToken;
@@ -124,6 +126,9 @@
private InputMethodManager mInputMethodManager;
+ private int mLastTouch[] = new int[2];
+ private int mDistanceSinceScroll = 0;
+
/**
* Interface to receive notifications when a drag starts or stops
*/
@@ -140,7 +145,7 @@
void onDragStart(DragSource source, Object info, int dragAction);
/**
- * The drag has eneded
+ * The drag has ended
*/
void onDragEnd();
}
@@ -156,9 +161,13 @@
mScrollZone = context.getResources().getDimensionPixelSize(R.dimen.scroll_zone);
}
+ public boolean dragging() {
+ return mDragging;
+ }
+
/**
* Starts a drag.
- *
+ *
* @param v The view that is being dragged
* @param source An object representing where the drag originated
* @param dragInfo The data associated with the object that is being dragged
@@ -166,6 +175,22 @@
* {@link #DRAG_ACTION_COPY}
*/
public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
+ startDrag(v, source, dragInfo, dragAction, null);
+ }
+
+ /**
+ * Starts a drag.
+ *
+ * @param v The view that is being dragged
+ * @param source An object representing where the drag originated
+ * @param dragInfo The data associated with the object that is being dragged
+ * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
+ * {@link #DRAG_ACTION_COPY}
+ * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
+ * Makes dragging feel more precise, e.g. you can clip out a transparent border
+ */
+ public void startDrag(View v, DragSource source, Object dragInfo, int dragAction,
+ Rect dragRegion) {
mOriginator = v;
Bitmap b = getViewBitmap(v);
@@ -181,7 +206,7 @@
int screenY = loc[1];
startDrag(b, screenX, screenY, 0, 0, b.getWidth(), b.getHeight(),
- source, dragInfo, dragAction);
+ source, dragInfo, dragAction, dragRegion);
b.recycle();
@@ -192,7 +217,36 @@
/**
* Starts a drag.
- *
+ *
+ * @param v The view that is being dragged
+ * @param bmp The bitmap that represents the view being dragged
+ * @param source An object representing where the drag originated
+ * @param dragInfo The data associated with the object that is being dragged
+ * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
+ * {@link #DRAG_ACTION_COPY}
+ * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
+ * Makes dragging feel more precise, e.g. you can clip out a transparent border
+ */
+ public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction,
+ Rect dragRegion) {
+ mOriginator = v;
+
+ int[] loc = mCoordinatesTemp;
+ v.getLocationOnScreen(loc);
+ int screenX = loc[0];
+ int screenY = loc[1];
+
+ startDrag(bmp, screenX, screenY, 0, 0, bmp.getWidth(), bmp.getHeight(),
+ source, dragInfo, dragAction, dragRegion);
+
+ if (dragAction == DRAG_ACTION_MOVE) {
+ v.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Starts a drag.
+ *
* @param b The bitmap to display as the drag image. It will be re-scaled to the
* enlarged size.
* @param screenX The x position on screen of the left-top of the bitmap.
@@ -209,6 +263,31 @@
public void startDrag(Bitmap b, int screenX, int screenY,
int textureLeft, int textureTop, int textureWidth, int textureHeight,
DragSource source, Object dragInfo, int dragAction) {
+ startDrag(b, screenX, screenY, textureLeft, textureTop, textureWidth, textureHeight,
+ source, dragInfo, dragAction, null);
+ }
+
+ /**
+ * Starts a drag.
+ *
+ * @param b The bitmap to display as the drag image. It will be re-scaled to the
+ * enlarged size.
+ * @param screenX The x position on screen of the left-top of the bitmap.
+ * @param screenY The y position on screen of the left-top of the bitmap.
+ * @param textureLeft The left edge of the region inside b to use.
+ * @param textureTop The top edge of the region inside b to use.
+ * @param textureWidth The width of the region inside b to use.
+ * @param textureHeight The height of the region inside b to use.
+ * @param source An object representing where the drag originated
+ * @param dragInfo The data associated with the object that is being dragged
+ * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
+ * {@link #DRAG_ACTION_COPY}
+ * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
+ * Makes dragging feel more precise, e.g. you can clip out a transparent border
+ */
+ public void startDrag(Bitmap b, int screenX, int screenY,
+ int textureLeft, int textureTop, int textureWidth, int textureHeight,
+ DragSource source, Object dragInfo, int dragAction, Rect dragRegion) {
if (PROFILE_DRAWING_DURING_DRAG) {
android.os.Debug.startMethodTracing("Launcher");
}
@@ -220,15 +299,17 @@
}
mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
- if (mListener != null) {
- mListener.onDragStart(source, dragInfo, dragAction);
+ for (DragListener listener : mListeners) {
+ listener.onDragStart(source, dragInfo, dragAction);
}
int registrationX = ((int)mMotionDownX) - screenX;
int registrationY = ((int)mMotionDownY) - screenY;
- mTouchOffsetX = mMotionDownX - screenX;
- mTouchOffsetY = 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;
mDragging = true;
mDragSource = source;
@@ -238,13 +319,28 @@
DragView dragView = mDragView = new DragView(mContext, b, registrationX, registrationY,
textureLeft, textureTop, textureWidth, textureHeight);
+
+ final DragSource dragSource = source;
+ dragView.setOnDrawRunnable(new Runnable() {
+ public void run() {
+ dragSource.onDragViewVisible();
+ };
+ });
+
+ if (dragRegion != null) {
+ dragView.setDragRegion(dragRegionLeft, dragRegion.top,
+ dragRegion.right - dragRegionLeft, dragRegion.bottom - dragRegionTop);
+ }
+
dragView.show(mWindowToken, (int)mMotionDownX, (int)mMotionDownY);
+
+ handleMoveEvent((int) mMotionDownX, (int) mMotionDownY);
}
/**
* Draw the view into a bitmap.
*/
- private Bitmap getViewBitmap(View v) {
+ Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
@@ -255,6 +351,8 @@
// for the duration of this operation
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
+ float alpha = v.getAlpha();
+ v.setAlpha(1.0f);
if (color != 0) {
v.destroyDrawingCache();
@@ -270,6 +368,7 @@
// Restore the view
v.destroyDrawingCache();
+ v.setAlpha(alpha);
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
@@ -291,10 +390,18 @@
return mDragging;
}
+ public boolean isDragging() {
+ return mDragging;
+ }
+
/**
* Stop dragging without dropping.
*/
public void cancelDrag() {
+ if (mDragging) {
+ // Should we also be calling onDragExit() here?
+ mDragSource.onDropCompleted(null, false);
+ }
endDrag();
}
@@ -304,8 +411,8 @@
if (mOriginator != null) {
mOriginator.setVisibility(View.VISIBLE);
}
- if (mListener != null) {
- mListener.onDragEnd();
+ for (DragListener listener : mListeners) {
+ listener.onDragEnd();
}
if (mDragView != null) {
mDragView.remove();
@@ -334,21 +441,21 @@
switch (action) {
case MotionEvent.ACTION_MOVE:
break;
-
case MotionEvent.ACTION_DOWN:
// Remember location of down touch
mMotionDownX = screenX;
mMotionDownY = screenY;
mLastDropTarget = null;
break;
-
- case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mDragging) {
drop(screenX, screenY);
}
endDrag();
break;
+ case MotionEvent.ACTION_CANCEL:
+ cancelDrag();
+ break;
}
return mDragging;
@@ -365,12 +472,80 @@
return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction);
}
+ private void handleMoveEvent(int x, int y) {
+ mDragView.move(x, y);
+
+ // Drop on someone?
+ final int[] coordinates = mCoordinatesTemp;
+ DropTarget dropTarget = findDropTarget(x, y, coordinates);
+ if (dropTarget != null) {
+ DropTarget delegate = dropTarget.getDropTargetDelegate(
+ mDragSource, coordinates[0], coordinates[1],
+ (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+ if (delegate != null) {
+ dropTarget = delegate;
+ }
+
+ if (mLastDropTarget != dropTarget) {
+ if (mLastDropTarget != null) {
+ mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
+ (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+ }
+ dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1],
+ (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+ }
+ dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
+ (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+ } else {
+ if (mLastDropTarget != null) {
+ mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
+ (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
+ }
+ }
+ mLastDropTarget = dropTarget;
+
+ // Scroll, maybe, but not if we're in the delete region.
+ boolean inDeleteRegion = false;
+ if (mDeleteRegion != null) {
+ inDeleteRegion = mDeleteRegion.contains(x, y);
+ }
+
+ // After a scroll, the touch point will still be in the scroll region.
+ // Rather than scrolling immediately, require a bit of twiddling to scroll again
+ final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
+ mDistanceSinceScroll +=
+ Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
+ mLastTouch[0] = x;
+ mLastTouch[1] = y;
+
+ if (!inDeleteRegion && x < mScrollZone) {
+ if (mScrollState == SCROLL_OUTSIDE_ZONE && mDistanceSinceScroll > slop) {
+ mScrollState = SCROLL_WAITING_IN_ZONE;
+ mScrollRunnable.setDirection(SCROLL_LEFT);
+ mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
+ mDragScroller.onEnterScrollArea(SCROLL_LEFT);
+ }
+ } else if (!inDeleteRegion && x > mScrollView.getWidth() - mScrollZone) {
+ if (mScrollState == SCROLL_OUTSIDE_ZONE && mDistanceSinceScroll > slop) {
+ mScrollState = SCROLL_WAITING_IN_ZONE;
+ mScrollRunnable.setDirection(SCROLL_RIGHT);
+ mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
+ mDragScroller.onEnterScrollArea(SCROLL_RIGHT);
+ }
+ } else {
+ if (mScrollState == SCROLL_WAITING_IN_ZONE) {
+ mScrollState = SCROLL_OUTSIDE_ZONE;
+ mScrollRunnable.setDirection(SCROLL_RIGHT);
+ mHandler.removeCallbacks(mScrollRunnable);
+ mDragScroller.onExitScrollArea();
+ }
+ }
+ }
+
/**
* Call this from a drag source view.
*/
public boolean onTouchEvent(MotionEvent ev) {
- View scrollView = mScrollView;
-
if (!mDragging) {
return false;
}
@@ -385,69 +560,15 @@
mMotionDownX = screenX;
mMotionDownY = screenY;
- if ((screenX < mScrollZone) || (screenX > scrollView.getWidth() - mScrollZone)) {
+ if ((screenX < mScrollZone) || (screenX > mScrollView.getWidth() - mScrollZone)) {
mScrollState = SCROLL_WAITING_IN_ZONE;
mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
} else {
mScrollState = SCROLL_OUTSIDE_ZONE;
}
-
break;
case MotionEvent.ACTION_MOVE:
- // Update the drag view. Don't use the clamped pos here so the dragging looks
- // like it goes off screen a little, intead of bumping up against the edge.
- mDragView.move((int)ev.getRawX(), (int)ev.getRawY());
-
- // Drop on someone?
- final int[] coordinates = mCoordinatesTemp;
- DropTarget dropTarget = findDropTarget(screenX, screenY, coordinates);
- if (dropTarget != null) {
- if (mLastDropTarget == dropTarget) {
- dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
- (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
- } else {
- if (mLastDropTarget != null) {
- mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
- (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
- }
- dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1],
- (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
- }
- } else {
- if (mLastDropTarget != null) {
- mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
- (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
- }
- }
- mLastDropTarget = dropTarget;
-
- // Scroll, maybe, but not if we're in the delete region.
- boolean inDeleteRegion = false;
- if (mDeleteRegion != null) {
- inDeleteRegion = mDeleteRegion.contains(screenX, screenY);
- }
- //Log.d(Launcher.TAG, "inDeleteRegion=" + inDeleteRegion + " screenX=" + screenX
- // + " mScrollZone=" + mScrollZone);
- if (!inDeleteRegion && screenX < mScrollZone) {
- if (mScrollState == SCROLL_OUTSIDE_ZONE) {
- mScrollState = SCROLL_WAITING_IN_ZONE;
- mScrollRunnable.setDirection(SCROLL_LEFT);
- mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
- }
- } else if (!inDeleteRegion && screenX > scrollView.getWidth() - mScrollZone) {
- if (mScrollState == SCROLL_OUTSIDE_ZONE) {
- mScrollState = SCROLL_WAITING_IN_ZONE;
- mScrollRunnable.setDirection(SCROLL_RIGHT);
- mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
- }
- } else {
- if (mScrollState == SCROLL_WAITING_IN_ZONE) {
- mScrollState = SCROLL_OUTSIDE_ZONE;
- mScrollRunnable.setDirection(SCROLL_RIGHT);
- mHandler.removeCallbacks(mScrollRunnable);
- }
- }
-
+ handleMoveEvent(screenX, screenY);
break;
case MotionEvent.ACTION_UP:
mHandler.removeCallbacks(mScrollRunnable);
@@ -455,10 +576,10 @@
drop(screenX, screenY);
}
endDrag();
-
break;
case MotionEvent.ACTION_CANCEL:
cancelDrag();
+ break;
}
return true;
@@ -481,6 +602,8 @@
mDragSource.onDropCompleted((View) dropTarget, false);
return true;
}
+ } else {
+ mDragSource.onDropCompleted(null, false);
}
return false;
}
@@ -491,13 +614,28 @@
final ArrayList<DropTarget> dropTargets = mDropTargets;
final int count = dropTargets.size();
for (int i=count-1; i>=0; i--) {
- final DropTarget target = dropTargets.get(i);
+ DropTarget target = dropTargets.get(i);
+ if (!target.isDropEnabled())
+ continue;
+
target.getHitRect(r);
+
+ // Convert the hit rect to screen coordinates
target.getLocationOnScreen(dropCoordinates);
r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
+
if (r.contains(x, y)) {
+ DropTarget delegate = target.getDropTargetDelegate(mDragSource,
+ x, y, (int)mTouchOffsetX, (int)mTouchOffsetY, mDragView, mDragInfo);
+ if (delegate != null) {
+ target = delegate;
+ target.getLocationOnScreen(dropCoordinates);
+ }
+
+ // Make dropCoordinates relative to the DropTarget
dropCoordinates[0] = x - dropCoordinates[0];
dropCoordinates[1] = y - dropCoordinates[1];
+
return target;
}
}
@@ -537,15 +675,15 @@
/**
* Sets the drag listner which will be notified when a drag starts or ends.
*/
- public void setDragListener(DragListener l) {
- mListener = l;
+ public void addDragListener(DragListener l) {
+ mListeners.add(l);
}
/**
* Remove a previously installed drag listener.
*/
public void removeDragListener(DragListener l) {
- mListener = null;
+ mListeners.remove(l);
}
/**
@@ -592,6 +730,8 @@
mDragScroller.scrollRight();
}
mScrollState = SCROLL_OUTSIDE_ZONE;
+ mDistanceSinceScroll = 0;
+ mDragScroller.onExitScrollArea();
}
}
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index c683207..b418a79 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -17,23 +17,26 @@
package com.android.launcher2;
import android.content.Context;
+import android.graphics.Bitmap;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
+import android.widget.ImageView;
/**
- * A ViewGroup that coordinated dragging across its dscendants
+ * A ViewGroup that coordinates dragging across its descendants
*/
public class DragLayer extends FrameLayout {
- DragController mDragController;
+ private DragController mDragController;
+ private int[] mTmpXY = new int[2];
/**
* Used to create a new DragLayer from XML.
*
* @param context The application's context.
- * @param attrs The attribtues set containing the Workspace's customization values.
+ * @param attrs The attributes set containing the Workspace's customization values.
*/
public DragLayer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -62,4 +65,19 @@
public boolean dispatchUnhandledMove(View focused, int direction) {
return mDragController.dispatchUnhandledMove(focused, direction);
}
+
+ public View createDragView(Bitmap b, int xPos, int yPos) {
+ ImageView imageView = new ImageView(mContext);
+ imageView.setImageBitmap(b);
+ imageView.setX(xPos);
+ imageView.setY(yPos);
+ addView(imageView, b.getWidth(), b.getHeight());
+
+ return imageView;
+ }
+
+ public View createDragView(View v) {
+ v.getLocationOnScreen(mTmpXY);
+ return createDragView(mDragController.getViewBitmap(v), mTmpXY[0], mTmpXY[1]);
+ }
}
diff --git a/src/com/android/launcher2/DragScroller.java b/src/com/android/launcher2/DragScroller.java
index c3c251c..6af9c30 100644
--- a/src/com/android/launcher2/DragScroller.java
+++ b/src/com/android/launcher2/DragScroller.java
@@ -23,4 +23,16 @@
public interface DragScroller {
void scrollLeft();
void scrollRight();
+
+ /**
+ * The touch point has entered the scroll area; a scroll is imminent.
+ *
+ * @param direction The scroll direction
+ */
+ void onEnterScrollArea(int direction);
+
+ /**
+ * The touch point has left the scroll area.
+ */
+ void onExitScrollArea();
}
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
index 7c6ca58..11cdcc9 100644
--- a/src/com/android/launcher2/DragSource.java
+++ b/src/com/android/launcher2/DragSource.java
@@ -24,5 +24,12 @@
*/
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.
+ */
+ void onDragViewVisible();
+
void onDropCompleted(View target, boolean success);
}
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index 248712e..433dab8 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -17,41 +17,52 @@
package com.android.launcher2;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
-import android.content.res.TypedArray;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.os.IBinder;
-import android.util.AttributeSet;
-import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
-import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
+import android.view.animation.DecelerateInterpolator;
-public class DragView extends View implements TweenCallback {
- // Number of pixels to add to the dragged item for scaling. Should be even for pixel alignment.
- private static final int DRAG_SCALE = 40;
+import com.android.launcher.R;
+public class DragView extends View {
private Bitmap mBitmap;
private Paint mPaint;
private int mRegistrationX;
private int mRegistrationY;
- SymmetricalLinearTween mTween;
- private float mScale;
- private float mAnimationScale = 1.0f;
+ private int mDragRegionLeft = 0;
+ private int mDragRegionTop = 0;
+ private int mDragRegionWidth;
+ private int mDragRegionHeight;
+
+ ValueAnimator mAnim;
+ private float mScale = 1.0f;
+ private float mOffsetX = 0.0f;
+ private float mOffsetY = 0.0f;
private WindowManager.LayoutParams mLayoutParams;
private WindowManager mWindowManager;
/**
+ * A callback to be called the first time this view is drawn.
+ * This allows the originator of the drag to dim or hide the original view as soon
+ * as the DragView is drawn.
+ */
+ private Runnable mOnDrawRunnable = null;
+
+ /**
* Construct the drag view.
* <p>
* The registration point is the point inside our view that the touch events should
@@ -66,20 +77,103 @@
int left, int top, int width, int height) {
super(context);
+ final Resources res = getResources();
+ final int dragScale = res.getInteger(R.integer.config_dragViewExtraPixels);
+
mWindowManager = WindowManagerImpl.getDefault();
-
- mTween = new SymmetricalLinearTween(false, 110 /*ms duration*/, this);
Matrix scale = new Matrix();
- float scaleFactor = width;
- scaleFactor = mScale = (scaleFactor + DRAG_SCALE) / scaleFactor;
- scale.setScale(scaleFactor, scaleFactor);
+ final float scaleFactor = (width + dragScale) / width;
+ if (scaleFactor != 1.0f) {
+ scale.setScale(scaleFactor, scaleFactor);
+ }
+
+ final int offsetX = res.getInteger(R.integer.config_dragViewOffsetX);
+ final int offsetY = res.getInteger(R.integer.config_dragViewOffsetY);
+
+ // Animate the view into the correct position
+ mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
+ mAnim.setDuration(110);
+ mAnim.setInterpolator(new DecelerateInterpolator(2.5f));
+ mAnim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float value = (Float) animation.getAnimatedValue();
+
+ final int deltaX = (int) ((value * offsetX) - mOffsetX);
+ final int deltaY = (int) ((value * offsetY) - mOffsetY);
+
+ mOffsetX += deltaX;
+ mOffsetY += deltaY;
+
+ if (getParent() == null) {
+ animation.cancel();
+ } else {
+ WindowManager.LayoutParams lp = mLayoutParams;
+ lp.x += deltaX;
+ lp.y += deltaY;
+ mWindowManager.updateViewLayout(DragView.this, lp);
+ }
+ }
+ });
mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height, scale, true);
+ setDragRegion(0, 0, width, height);
// The point in our scaled bitmap that the touch events are located
- mRegistrationX = registrationX + (DRAG_SCALE / 2);
- mRegistrationY = registrationY + (DRAG_SCALE / 2);
+ mRegistrationX = registrationX;
+ mRegistrationY = registrationY;
+
+ // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
+ int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+ measure(ms, ms);
+ }
+
+ public float getOffsetY() {
+ 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 getScaledDragRegionXOffset() {
+ return -(int)((mScale - 1.0f) * mDragRegionWidth / 2);
+ }
+
+ public int getScaledDragRegionWidth() {
+ return (int)(mScale * mDragRegionWidth);
+ }
+
+ public int getScaledDragRegionYOffset() {
+ return -(int)((mScale - 1.0f) * mDragRegionHeight / 2);
+ }
+
+ public int getScaledDragRegionHeight() {
+ return (int)(mScale * mDragRegionWidth);
+ }
+
+ public int getDragRegionLeft() {
+ return mDragRegionLeft;
+ }
+
+ public int getDragRegionTop() {
+ return mDragRegionTop;
+ }
+
+ public int getDragRegionWidth() {
+ return mDragRegionWidth;
+ }
+
+ public int getDragRegionHeight() {
+ return mDragRegionHeight;
}
@Override
@@ -96,13 +190,15 @@
p.setColor(0xaaffffff);
canvas.drawRect(0, 0, getWidth(), getHeight(), p);
}
- float scale = mAnimationScale;
- if (scale < 0.999f) { // allow for some float error
- float width = mBitmap.getWidth();
- float offset = (width-(width*scale))/2;
- canvas.translate(offset, offset);
- canvas.scale(scale, scale);
+
+ // Call the callback if we haven't already been detached
+ if (getParent() != null) {
+ if (mOnDrawRunnable != null) {
+ mOnDrawRunnable.run();
+ mOnDrawRunnable = null;
+ }
}
+
canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
}
@@ -112,17 +208,6 @@
mBitmap.recycle();
}
- public void onTweenValueChanged(float value, float oldValue) {
- mAnimationScale = (1.0f+((mScale-1.0f)*value))/mScale;
- invalidate();
- }
-
- public void onTweenStarted() {
- }
-
- public void onTweenFinished() {
- }
-
public void setPaint(Paint paint) {
mPaint = paint;
invalidate();
@@ -144,7 +229,7 @@
lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
- touchX-mRegistrationX, touchY-mRegistrationY,
+ touchX - mRegistrationX, touchY - mRegistrationY,
WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -158,8 +243,7 @@
mWindowManager.addView(this, lp);
- mAnimationScale = 1.0f/mScale;
- mTween.start(true);
+ mAnim.start();
}
/**
@@ -170,8 +254,8 @@
*/
void move(int touchX, int touchY) {
WindowManager.LayoutParams lp = mLayoutParams;
- lp.x = touchX - mRegistrationX;
- lp.y = touchY - mRegistrationY;
+ lp.x = touchX - mRegistrationX + (int) mOffsetX;
+ lp.y = touchY - mRegistrationY + (int) mOffsetY;
mWindowManager.updateViewLayout(this, lp);
}
diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java
index 72eb330..308dbbe 100644
--- a/src/com/android/launcher2/DropTarget.java
+++ b/src/com/android/launcher2/DropTarget.java
@@ -23,6 +23,12 @@
*
*/
public interface DropTarget {
+ /**
+ * Used to temporarily disable certain drop targets
+ *
+ * @return boolean specifying whether this drop target is currently enabled
+ */
+ boolean isDropEnabled();
/**
* Handle an object being dropped on the DropTarget
@@ -51,9 +57,28 @@
DragView dragView, Object dragInfo);
/**
+ * Allows a DropTarget to delegate drag and drop events to another object.
+ *
+ * Most subclasses will should just return null from this method.
+ *
+ * @param source DragSource where the drag started
+ * @param x X coordinate of the drop location
+ * @param y Y coordinate of the drop location
+ * @param xOffset Horizontal offset with the object being dragged where the original
+ * touch happened
+ * @param yOffset Vertical offset with the object being dragged where the original
+ * touch happened
+ * @param dragView The DragView that's being dragged around on screen.
+ * @param dragInfo Data associated with the object being dragged
+ *
+ * @return The DropTarget to delegate to, or null to not delegate to another object.
+ */
+ DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo);
+
+ /**
* Check if a drop action can occur at, or near, the requested location.
- * This may be called repeatedly during a drag, so any calls should return
- * quickly.
+ * This will be called just before onDrop.
*
* @param source DragSource where the drag started
* @param x X coordinate of the drop location
@@ -69,27 +94,6 @@
boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo);
- /**
- * Estimate the surface area where this object would land if dropped at the
- * given location.
- *
- * @param source DragSource where the drag started
- * @param x X coordinate of the drop location
- * @param y Y coordinate of the drop location
- * @param xOffset Horizontal offset with the object being dragged where the
- * original touch happened
- * @param yOffset Vertical offset with the object being dragged where the
- * original touch happened
- * @param dragView The DragView that's being dragged around on screen.
- * @param dragInfo Data associated with the object being dragged
- * @param recycle {@link Rect} object to be possibly recycled.
- * @return Estimated area that would be occupied if object was dropped at
- * the given location. Should return null if no estimate is found,
- * or if this target doesn't provide estimations.
- */
- Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo, Rect recycle);
-
// These methods are implemented in Views
void getHitRect(Rect outRect);
void getLocationOnScreen(int[] loc);
diff --git a/src/com/android/launcher2/FastBitmapDrawable.java b/src/com/android/launcher2/FastBitmapDrawable.java
index 226d6d8..a453294 100644
--- a/src/com/android/launcher2/FastBitmapDrawable.java
+++ b/src/com/android/launcher2/FastBitmapDrawable.java
@@ -16,18 +16,23 @@
package com.android.launcher2;
-import android.graphics.drawable.Drawable;
-import android.graphics.PixelFormat;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
class FastBitmapDrawable extends Drawable {
private Bitmap mBitmap;
+ private int mAlpha;
private int mWidth;
private int mHeight;
+ private final Paint mPaint = new Paint();
FastBitmapDrawable(Bitmap b) {
+ mAlpha = 255;
mBitmap = b;
if (b != null) {
mWidth = mBitmap.getWidth();
@@ -39,7 +44,8 @@
@Override
public void draw(Canvas canvas) {
- canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
+ final Rect r = getBounds();
+ canvas.drawBitmap(mBitmap, r.left, r.top, mPaint);
}
@Override
@@ -49,6 +55,12 @@
@Override
public void setAlpha(int alpha) {
+ mAlpha = alpha;
+ mPaint.setAlpha(alpha);
+ }
+
+ public int getAlpha() {
+ return mAlpha;
}
@Override
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 7ff8328..cb450b9 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -21,11 +21,11 @@
import android.util.AttributeSet;
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.AbsListView;
-import android.widget.BaseAdapter;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
@@ -108,13 +108,19 @@
return true;
}
+ @Override
public void setDragController(DragController dragController) {
mDragController = dragController;
}
+ @Override
public void onDropCompleted(View target, boolean success) {
}
+ @Override
+ public void onDragViewVisible() {
+ }
+
/**
* Sets the adapter used to populate the content area. The adapter must only
* contains ShortcutInfo items.
@@ -148,7 +154,7 @@
void onClose() {
final Workspace workspace = mLauncher.getWorkspace();
- workspace.getChildAt(workspace.getCurrentScreen()).requestFocus();
+ workspace.getChildAt(workspace.getCurrentPage()).requestFocus();
}
void bind(FolderInfo info) {
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index 0013644..dd83c78 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -43,15 +42,19 @@
super(context);
}
+ public boolean isDropEnabled() {
+ return !((Workspace)getParent().getParent()).isSmall();
+ }
+
static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
- UserFolderInfo folderInfo) {
+ UserFolderInfo folderInfo, IconCache iconCache) {
FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
final Resources resources = launcher.getResources();
- Drawable d = resources.getDrawable(R.drawable.ic_launcher_folder);
+ Drawable d = iconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder);
icon.mCloseIcon = d;
- icon.mOpenIcon = resources.getDrawable(R.drawable.ic_launcher_folder_open);
+ icon.mOpenIcon = iconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder_open);
icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);
icon.setText(folderInfo.title);
icon.setTag(folderInfo);
@@ -71,11 +74,6 @@
&& item.container != mInfo.id;
}
- public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo, Rect recycle) {
- return null;
- }
-
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
ShortcutInfo item;
@@ -91,7 +89,9 @@
public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
- setCompoundDrawablesWithIntrinsicBounds(null, mOpenIcon, null, null);
+ 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,
@@ -102,4 +102,10 @@
DragView dragView, Object dragInfo) {
setCompoundDrawablesWithIntrinsicBounds(null, mCloseIcon, null, null);
}
+
+ @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/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java
new file mode 100644
index 0000000..1efc123
--- /dev/null
+++ b/src/com/android/launcher2/HolographicOutlineHelper.java
@@ -0,0 +1,221 @@
+/*
+ * 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.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.MaskFilter;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.TableMaskFilter;
+
+public class HolographicOutlineHelper {
+ private final Paint mHolographicPaint = new Paint();
+ private final Paint mBlurPaint = new Paint();
+ private final Paint mErasePaint = new Paint();
+ private final Paint mAlphaClipPaint = new Paint();
+
+ public static final int MAX_OUTER_BLUR_RADIUS;
+
+ private static final BlurMaskFilter sExtraThickOuterBlurMaskFilter;
+ private static final BlurMaskFilter sThickOuterBlurMaskFilter;
+ private static final BlurMaskFilter sMediumOuterBlurMaskFilter;
+ private static final BlurMaskFilter sThinOuterBlurMaskFilter;
+ private static final BlurMaskFilter sThickInnerBlurMaskFilter;
+ private static final BlurMaskFilter sExtraThickInnerBlurMaskFilter;
+ private static final BlurMaskFilter sMediumInnerBlurMaskFilter;
+
+ private static final int THICK = 0;
+ private static final int MEDIUM = 1;
+ private static final int EXTRA_THICK = 2;
+
+ static {
+ final float scale = LauncherApplication.getScreenDensity();
+
+ MAX_OUTER_BLUR_RADIUS = (int) (scale * 12.0f);
+
+ sExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
+ sThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER);
+ sMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
+ sThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
+ sExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL);
+ sThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
+ sMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
+ }
+
+ private static final MaskFilter sCoarseClipTable = TableMaskFilter.CreateClipTable(0, 200);
+
+ private int[] mTempOffset = new int[2];
+
+ HolographicOutlineHelper() {
+ mHolographicPaint.setFilterBitmap(true);
+ mHolographicPaint.setAntiAlias(true);
+ mBlurPaint.setFilterBitmap(true);
+ mBlurPaint.setAntiAlias(true);
+ mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+ mErasePaint.setFilterBitmap(true);
+ mErasePaint.setAntiAlias(true);
+ MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(180, 255);
+ mAlphaClipPaint.setMaskFilter(alphaClipTable);
+ }
+
+ /**
+ * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
+ * pages.
+ */
+ public float highlightAlphaInterpolator(float r) {
+ float maxAlpha = 0.8f;
+ return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
+ }
+
+ /**
+ * Returns the interpolated view alpha for the effect we want when scrolling pages.
+ */
+ public float viewAlphaInterpolator(float r) {
+ final float pivot = 0.95f;
+ if (r < pivot) {
+ return (float) Math.pow(r / pivot, 1.5f);
+ } else {
+ return 1.0f;
+ }
+ }
+
+ /**
+ * Apply an outer blur to the given bitmap.
+ * You should use OUTER_BLUR_RADIUS to ensure that the bitmap is big enough to draw
+ * the blur without clipping.
+ */
+ void applyOuterBlur(Bitmap bitmap, Canvas canvas, int color) {
+ mBlurPaint.setMaskFilter(sThickOuterBlurMaskFilter);
+ Bitmap glow = bitmap.extractAlpha(mBlurPaint, mTempOffset);
+
+ // Use the clip table to make the glow heavier closer to the outline
+ mHolographicPaint.setMaskFilter(sCoarseClipTable);
+ mHolographicPaint.setAlpha(150);
+ mHolographicPaint.setColor(color);
+
+ canvas.drawBitmap(glow, mTempOffset[0], mTempOffset[1], mHolographicPaint);
+ glow.recycle();
+ }
+
+ /**
+ * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
+ * bitmap.
+ */
+ void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
+ int outlineColor, int thickness) {
+
+ // We start by removing most of the alpha channel so as to ignore shadows, and
+ // other types of partial transparency when defining the shape of the object
+ Bitmap glowShape = srcDst.extractAlpha(mAlphaClipPaint, mTempOffset);
+
+ // calculate the outer blur first
+ BlurMaskFilter outerBlurMaskFilter;
+ switch (thickness) {
+ case EXTRA_THICK:
+ outerBlurMaskFilter = sExtraThickOuterBlurMaskFilter;
+ break;
+ case THICK:
+ outerBlurMaskFilter = sThickOuterBlurMaskFilter;
+ break;
+ case MEDIUM:
+ outerBlurMaskFilter = sMediumOuterBlurMaskFilter;
+ break;
+ default:
+ throw new RuntimeException("Invalid blur thickness");
+ }
+ mBlurPaint.setMaskFilter(outerBlurMaskFilter);
+ int[] outerBlurOffset = new int[2];
+ Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
+ if (thickness == EXTRA_THICK) {
+ mBlurPaint.setMaskFilter(sMediumOuterBlurMaskFilter);
+ } else {
+ mBlurPaint.setMaskFilter(sThinOuterBlurMaskFilter);
+ }
+
+ int[] brightOutlineOffset = new int[2];
+ Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
+
+ // calculate the inner blur
+ srcDstCanvas.setBitmap(glowShape);
+ srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
+ BlurMaskFilter innerBlurMaskFilter;
+ switch (thickness) {
+ case EXTRA_THICK:
+ innerBlurMaskFilter = sExtraThickInnerBlurMaskFilter;
+ break;
+ case THICK:
+ innerBlurMaskFilter = sThickInnerBlurMaskFilter;
+ break;
+ case MEDIUM:
+ innerBlurMaskFilter = sMediumInnerBlurMaskFilter;
+ break;
+ default:
+ throw new RuntimeException("Invalid blur thickness");
+ }
+ mBlurPaint.setMaskFilter(innerBlurMaskFilter);
+ int[] thickInnerBlurOffset = new int[2];
+ Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
+
+ // mask out the inner blur
+ srcDstCanvas.setBitmap(thickInnerBlur);
+ srcDstCanvas.drawBitmap(glowShape, -thickInnerBlurOffset[0],
+ -thickInnerBlurOffset[1], mErasePaint);
+ srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
+ mErasePaint);
+ srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
+ mErasePaint);
+
+ // draw the inner and outer blur
+ srcDstCanvas.setBitmap(srcDst);
+ srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
+ mHolographicPaint.setColor(color);
+ srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
+ mHolographicPaint);
+ srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
+ mHolographicPaint);
+
+ // draw the bright outline
+ mHolographicPaint.setColor(outlineColor);
+ srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
+ mHolographicPaint);
+
+ // cleanup
+ brightOutline.recycle();
+ thickOuterBlur.recycle();
+ thickInnerBlur.recycle();
+ glowShape.recycle();
+ }
+
+ void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
+ int outlineColor) {
+ applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK);
+ }
+
+ void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
+ int outlineColor) {
+ applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK);
+ }
+
+ void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
+ int outlineColor) {
+ applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM);
+ }
+
+}
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
index 81a786c..2e47adc 100644
--- a/src/com/android/launcher2/IconCache.java
+++ b/src/com/android/launcher2/IconCache.java
@@ -20,9 +20,11 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.util.DisplayMetrics;
import java.util.HashMap;
@@ -46,16 +48,49 @@
private final Utilities.BubbleText mBubble;
private final HashMap<ComponentName, CacheEntry> mCache =
new HashMap<ComponentName, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
+ private int mIconDpi;
public IconCache(LauncherApplication context) {
mContext = context;
mPackageManager = context.getPackageManager();
mBubble = new Utilities.BubbleText(context);
+ if (LauncherApplication.isScreenXLarge()) {
+ mIconDpi = DisplayMetrics.DENSITY_HIGH;
+ } else {
+ mIconDpi = context.getResources().getDisplayMetrics().densityDpi;
+ }
+ // need to set mIconDpi before getting default icon
mDefaultIcon = makeDefaultIcon();
}
+ public Drawable getFullResDefaultActivityIcon() {
+ return getFullResIcon(Resources.getSystem(),
+ com.android.internal.R.mipmap.sym_def_app_icon);
+ }
+
+ public Drawable getFullResIcon(Resources resources, int iconId) {
+ return resources.getDrawableForDensity(iconId, mIconDpi);
+ }
+
+ public Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) {
+ Resources resources;
+ try {
+ resources = packageManager.getResourcesForApplication(
+ info.activityInfo.applicationInfo);
+ } catch (PackageManager.NameNotFoundException e) {
+ resources = null;
+ }
+ if (resources != null) {
+ int iconId = info.activityInfo.getIconResource();
+ if (iconId != 0) {
+ return getFullResIcon(resources, iconId);
+ }
+ }
+ return getFullResDefaultActivityIcon();
+ }
+
private Bitmap makeDefaultIcon() {
- Drawable d = mPackageManager.getDefaultActivityIcon();
+ Drawable d = getFullResDefaultActivityIcon();
Bitmap b = Bitmap.createBitmap(Math.max(d.getIntrinsicWidth(), 1),
Math.max(d.getIntrinsicHeight(), 1),
Bitmap.Config.ARGB_8888);
@@ -140,7 +175,7 @@
entry.title = info.activityInfo.name;
}
entry.icon = Utilities.createIconBitmap(
- info.activityInfo.loadIcon(mPackageManager), mContext);
+ getFullResIcon(info, mPackageManager), mContext);
}
return entry;
}
diff --git a/src/com/android/launcher2/IconDropTarget.java b/src/com/android/launcher2/IconDropTarget.java
new file mode 100644
index 0000000..fb5d0f0
--- /dev/null
+++ b/src/com/android/launcher2/IconDropTarget.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+
+/**
+ * Implements a DropTarget which allows applications to be dropped on it,
+ * in order to launch the application info for that app.
+ */
+public class IconDropTarget extends TextView implements DropTarget, DragController.DragListener {
+ protected Launcher mLauncher;
+
+ /**
+ * If true, this View responsible for managing its own visibility, and that of its overlapping
+ * views. This is generally the case, but it will be set to false when this is part of the
+ * Contextual Action Bar.
+ */
+ protected boolean mDragAndDropEnabled;
+
+ /** Whether this drop target is active for the current drag */
+ protected boolean mActive;
+
+ /** The views that this view should appear in the place of. */
+ protected View[] mOverlappingViews = null;
+
+ /** The paint applied to the drag view on hover */
+ protected final Paint mHoverPaint = new Paint();
+
+ /** Drag zone padding [T, R, B, L] */
+ protected final int mDragPadding[] = new int[4];
+
+ public IconDropTarget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public IconDropTarget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mDragAndDropEnabled = true;
+ }
+
+ protected void setDragPadding(int t, int r, int b, int l) {
+ mDragPadding[0] = t;
+ mDragPadding[1] = r;
+ mDragPadding[2] = b;
+ mDragPadding[3] = l;
+ }
+
+ void setLauncher(Launcher launcher) {
+ mLauncher = launcher;
+ }
+
+ void setOverlappingView(View view) {
+ mOverlappingViews = new View[] { view };
+ }
+
+ void setOverlappingViews(View[] views) {
+ mOverlappingViews = views;
+ }
+
+ void setDragAndDropEnabled(boolean enabled) {
+ mDragAndDropEnabled = enabled;
+ }
+
+ public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ return false;
+ }
+
+ public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ // Do nothing
+ }
+
+ public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ if (mDragAndDropEnabled) {
+ dragView.setPaint(mHoverPaint);
+ }
+ }
+
+ public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ // Do nothing
+ }
+
+ public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+ if (mDragAndDropEnabled) {
+ dragView.setPaint(null);
+ }
+ }
+
+ public void onDragStart(DragSource source, Object info, int dragAction) {
+ // Do nothing
+ }
+
+ public boolean isDropEnabled() {
+ return mDragAndDropEnabled && mActive;
+ }
+
+ public void onDragEnd() {
+ // Do nothing
+ }
+
+ @Override
+ public void getHitRect(Rect outRect) {
+ super.getHitRect(outRect);
+ if (LauncherApplication.isScreenXLarge()) {
+ outRect.top -= mDragPadding[0];
+ outRect.right += mDragPadding[1];
+ outRect.bottom += mDragPadding[2];
+ outRect.left -= mDragPadding[3];
+ }
+ }
+
+ @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/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java
index 3fc568b..ac50f66 100644
--- a/src/com/android/launcher2/InstallShortcutReceiver.java
+++ b/src/com/android/launcher2/InstallShortcutReceiver.java
@@ -16,19 +16,23 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.ContentResolver;
-import android.database.Cursor;
import android.widget.Toast;
import com.android.launcher.R;
public class InstallShortcutReceiver extends BroadcastReceiver {
- private static final String ACTION_INSTALL_SHORTCUT =
+ public static final String ACTION_INSTALL_SHORTCUT =
"com.android.launcher.action.INSTALL_SHORTCUT";
+ // A mime-type representing shortcut data
+ public static final String SHORTCUT_MIMETYPE =
+ "com.android.launcher/shortcut";
+
private final int[] mCoordinates = new int[2];
public void onReceive(Context context, Intent data) {
@@ -50,11 +54,6 @@
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
if (findEmptyCell(context, mCoordinates, screen)) {
- CellLayout.CellInfo cell = new CellLayout.CellInfo();
- cell.cellX = mCoordinates[0];
- cell.cellY = mCoordinates[1];
- cell.screen = screen;
-
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
if (intent.getAction() == null) {
@@ -66,7 +65,7 @@
boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);
if (duplicate || !LauncherModel.shortcutExists(context, name, intent)) {
((LauncherApplication)context.getApplicationContext()).getModel()
- .addShortcut(context, data, cell, true);
+ .addShortcut(context, data, screen, mCoordinates[0], mCoordinates[1], true);
Toast.makeText(context, context.getString(R.string.shortcut_installed, name),
Toast.LENGTH_SHORT).show();
} else {
@@ -84,40 +83,26 @@
}
private static boolean findEmptyCell(Context context, int[] xy, int screen) {
- final int xCount = Launcher.NUMBER_CELLS_X;
- final int yCount = Launcher.NUMBER_CELLS_Y;
-
+ final int xCount = LauncherModel.getCellCountX();
+ final int yCount = LauncherModel.getCellCountY();
boolean[][] occupied = new boolean[xCount][yCount];
- final ContentResolver cr = context.getContentResolver();
- Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
- LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY },
- LauncherSettings.Favorites.SCREEN + "=?",
- new String[] { String.valueOf(screen) }, null);
-
- final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
- final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
-
- try {
- while (c.moveToNext()) {
- int cellX = c.getInt(cellXIndex);
- int cellY = c.getInt(cellYIndex);
- int spanX = c.getInt(spanXIndex);
- int spanY = c.getInt(spanYIndex);
-
+ ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
+ ItemInfo item = null;
+ int cellX, cellY, spanX, spanY;
+ for (int i = 0; i < items.size(); ++i) {
+ item = items.get(i);
+ if (item.screen == screen) {
+ cellX = item.cellX;
+ cellY = item.cellY;
+ spanX = item.spanX;
+ spanY = item.spanY;
for (int x = cellX; x < cellX + spanX && x < xCount; x++) {
for (int y = cellY; y < cellY + spanY && y < yCount; y++) {
occupied[x][y] = true;
}
}
}
- } catch (Exception e) {
- return false;
- } finally {
- c.close();
}
return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);
diff --git a/src/com/android/launcher2/InstallWidgetReceiver.java b/src/com/android/launcher2/InstallWidgetReceiver.java
new file mode 100644
index 0000000..4f6cb8d
--- /dev/null
+++ b/src/com/android/launcher2/InstallWidgetReceiver.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import java.util.List;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ClipData;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import com.android.launcher.R;
+
+
+/**
+ * We will likely flesh this out later, to handle allow external apps to place widgets, but for now,
+ * we just want to expose the action around for checking elsewhere.
+ */
+public class InstallWidgetReceiver {
+ public static final String ACTION_INSTALL_WIDGET =
+ "com.android.launcher.action.INSTALL_WIDGET";
+ public static final String ACTION_SUPPORTS_CLIPDATA_MIMETYPE =
+ "com.android.launcher.action.SUPPORTS_CLIPDATA_MIMETYPE";
+
+ // Currently not exposed. Put into Intent when we want to make it public.
+ // TEMP: Should we call this "EXTRA_APPWIDGET_PROVIDER"?
+ public static final String EXTRA_APPWIDGET_COMPONENT =
+ "com.android.launcher.extra.widget.COMPONENT";
+ public static final String EXTRA_APPWIDGET_CONFIGURATION_DATA_MIME_TYPE =
+ "com.android.launcher.extra.widget.CONFIGURATION_DATA_MIME_TYPE";
+ public static final String EXTRA_APPWIDGET_CONFIGURATION_DATA =
+ "com.android.launcher.extra.widget.CONFIGURATION_DATA";
+
+ /**
+ * A simple data class that contains per-item information that the adapter below can reference.
+ */
+ public static class WidgetMimeTypeHandlerData {
+ public ResolveInfo resolveInfo;
+ public AppWidgetProviderInfo widgetInfo;
+
+ public WidgetMimeTypeHandlerData(ResolveInfo rInfo, AppWidgetProviderInfo wInfo) {
+ resolveInfo = rInfo;
+ widgetInfo = wInfo;
+ }
+ }
+
+ /**
+ * The ListAdapter which presents all the valid widgets that can be created for a given drop.
+ */
+ public static class WidgetListAdapter implements ListAdapter, DialogInterface.OnClickListener {
+ private LayoutInflater mInflater;
+ private Launcher mLauncher;
+ private String mMimeType;
+ private ClipData mClipData;
+ private List<WidgetMimeTypeHandlerData> mActivities;
+ private CellLayout mTargetLayout;
+ private int mTargetLayoutScreen;
+ private int[] mTargetLayoutPos;
+
+ public WidgetListAdapter(Launcher l, String mimeType, ClipData data,
+ List<WidgetMimeTypeHandlerData> list, CellLayout target,
+ int targetScreen, int[] targetPos) {
+ mLauncher = l;
+ mMimeType = mimeType;
+ mClipData = data;
+ mActivities = list;
+ mTargetLayout = target;
+ mTargetLayoutScreen = targetScreen;
+ mTargetLayoutPos = targetPos;
+ }
+
+ @Override
+ public void registerDataSetObserver(DataSetObserver observer) {
+ }
+
+ @Override
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+ }
+
+ @Override
+ public int getCount() {
+ return mActivities.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final Context context = parent.getContext();
+ final PackageManager packageManager = context.getPackageManager();
+
+ // Lazy-create inflater
+ if (mInflater == null) {
+ mInflater = LayoutInflater.from(context);
+ }
+
+ // Use the convert-view where possible
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.external_widget_drop_list_item, parent,
+ false);
+ }
+
+ final WidgetMimeTypeHandlerData data = mActivities.get(position);
+ final ResolveInfo resolveInfo = data.resolveInfo;
+ final AppWidgetProviderInfo widgetInfo = data.widgetInfo;
+
+ // Set the icon
+ Drawable d = resolveInfo.loadIcon(packageManager);
+ ImageView i = (ImageView) convertView.findViewById(R.id.provider_icon);
+ i.setImageDrawable(d);
+
+ // Set the text
+ final CharSequence component = resolveInfo.loadLabel(packageManager);
+ final int[] widgetSpan = new int[2];
+ mTargetLayout.rectToCell(widgetInfo.minWidth, widgetInfo.minHeight, widgetSpan);
+ TextView t = (TextView) convertView.findViewById(R.id.provider);
+ t.setText(context.getString(R.string.external_drop_widget_pick_format,
+ component, widgetSpan[0], widgetSpan[1]));
+
+ return convertView;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return 0;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 1;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return mActivities.isEmpty();
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return true;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final AppWidgetProviderInfo widgetInfo = mActivities.get(which).widgetInfo;
+
+ final PendingAddWidgetInfo createInfo = new PendingAddWidgetInfo(widgetInfo, mMimeType,
+ mClipData);
+ mLauncher.addAppWidgetFromDrop(createInfo, mTargetLayoutScreen, mTargetLayoutPos);
+ }
+ }
+}
diff --git a/src/com/android/launcher2/InterruptibleInOutAnimator.java b/src/com/android/launcher2/InterruptibleInOutAnimator.java
new file mode 100644
index 0000000..135fa39
--- /dev/null
+++ b/src/com/android/launcher2/InterruptibleInOutAnimator.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+
+/**
+ * A convenience class for two-way animations, e.g. a fadeIn/fadeOut animation.
+ * With a regular ValueAnimator, if you call reverse to show the 'out' animation, you'll get
+ * a frame-by-frame mirror of the 'in' animation -- i.e., the interpolated values will
+ * be exactly reversed. Using this class, both the 'in' and the 'out' animation use the
+ * interpolator in the same direction.
+ */
+public class InterruptibleInOutAnimator {
+ private long mOriginalDuration;
+ private float mOriginalFromValue;
+ private float mOriginalToValue;
+ private ValueAnimator mAnimator;
+
+ private boolean mFirstRun = true;
+
+ private Object mTag = null;
+
+ private static final int STOPPED = 0;
+ private static final int IN = 1;
+ private static final int OUT = 2;
+
+ // TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz
+ private int mDirection = STOPPED;
+
+ public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) {
+ mAnimator = ValueAnimator.ofFloat(fromValue, toValue).setDuration(duration);
+ mOriginalDuration = duration;
+ mOriginalFromValue = fromValue;
+ mOriginalToValue = toValue;
+
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDirection = STOPPED;
+ }
+ });
+ }
+
+ private void animate(int direction) {
+ final long currentPlayTime = mAnimator.getCurrentPlayTime();
+ final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue;
+ final float startValue = mFirstRun ? mOriginalFromValue :
+ ((Float) mAnimator.getAnimatedValue()).floatValue();
+
+ // Make sure it's stopped before we modify any values
+ cancel();
+
+ // TODO: We don't really need to do the animation if startValue == toValue, but
+ // somehow that doesn't seem to work, possibly a quirk of the animation framework
+ mDirection = direction;
+
+ // Ensure we don't calculate a non-sensical duration
+ long duration = mOriginalDuration - currentPlayTime;
+ mAnimator.setDuration(Math.max(0, Math.min(duration, mOriginalDuration)));
+
+ mAnimator.setFloatValues(startValue, toValue);
+ mAnimator.start();
+ mFirstRun = false;
+ }
+
+ public void cancel() {
+ mAnimator.cancel();
+ mDirection = STOPPED;
+ }
+
+ public void end() {
+ mAnimator.end();
+ mDirection = STOPPED;
+ }
+
+ /**
+ * Return true when the animation is not running and it hasn't even been started.
+ */
+ public boolean isStopped() {
+ return mDirection == STOPPED;
+ }
+
+ /**
+ * This is the equivalent of calling Animator.start(), except that it can be called when
+ * the animation is running in the opposite direction, in which case we reverse
+ * direction and animate for a correspondingly shorter duration.
+ */
+ public void animateIn() {
+ animate(IN);
+ }
+
+ /**
+ * This is the roughly the equivalent of calling Animator.reverse(), except that it uses the
+ * same interpolation curve as animateIn(), rather than mirroring it. Also, like animateIn(),
+ * if the animation is currently running in the opposite direction, we reverse
+ * direction and animate for a correspondingly shorter duration.
+ */
+ public void animateOut() {
+ animate(OUT);
+ }
+
+ public void setTag(Object tag) {
+ mTag = tag;
+ }
+
+ public Object getTag() {
+ return mTag;
+ }
+
+ public ValueAnimator getAnimator() {
+ return mAnimator;
+ }
+}
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index a96d9ae..dc45750 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -112,6 +112,11 @@
}
}
+ void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) {
+ values.put(LauncherSettings.Favorites.CELLX, cellX);
+ values.put(LauncherSettings.Favorites.CELLY, cellY);
+ }
+
static byte[] flattenBitmap(Bitmap bitmap) {
// Try go guesstimate how much space the icon will take when serialized
// to avoid unnecessary allocations/copies during the write.
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index e611303..f381b1f 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2008 The Android Open Source Project
*
@@ -16,16 +17,31 @@
package com.android.launcher2;
-import com.android.common.Search;
+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;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.SearchManager;
import android.app.StatusBarManager;
-import android.app.WallpaperManager;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
+import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -35,24 +51,29 @@
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+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;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -64,34 +85,39 @@
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.Surface;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.InputMethodManager;
+import android.widget.Advanceable;
import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+import android.widget.TabHost;
+import android.widget.TabHost.OnTabChangeListener;
+import android.widget.TabHost.TabContentFactory;
+import android.widget.TabWidget;
import android.widget.TextView;
import android.widget.Toast;
-import android.widget.ImageView;
-import android.widget.PopupWindow;
-import android.widget.LinearLayout;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.HashMap;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.DataInputStream;
-
+import com.android.common.Search;
import com.android.launcher.R;
+import com.android.launcher2.CustomizePagedView.CustomizationType;
+import com.android.launcher2.Workspace.ShrinkState;
+
/**
* Default launcher application.
*/
public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {
+ implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
+ AllAppsView.Watcher, View.OnTouchListener {
static final String TAG = "Launcher";
static final boolean LOGD = false;
@@ -99,8 +125,6 @@
static final boolean DEBUG_WIDGETS = false;
static final boolean DEBUG_USER_INTERFACE = false;
- private static final int WALLPAPER_SCREENS_SPAN = 2;
-
private static final int MENU_GROUP_ADD = 1;
private static final int MENU_GROUP_WALLPAPER = MENU_GROUP_ADD + 1;
@@ -124,8 +148,6 @@
static final int SCREEN_COUNT = 5;
static final int DEFAULT_SCREEN = 2;
- static final int NUMBER_CELLS_X = 4;
- static final int NUMBER_CELLS_Y = 4;
static final int DIALOG_CREATE_SHORTCUT = 1;
static final int DIALOG_RENAME_FOLDER = 2;
@@ -134,8 +156,8 @@
// Type: int
private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
- // Type: boolean
- private static final String RUNTIME_STATE_ALL_APPS_FOLDER = "launcher.all_apps_folder";
+ // Type: int
+ private static final String RUNTIME_STATE = "launcher.state";
// Type: long
private static final String RUNTIME_STATE_USER_FOLDERS = "launcher.user_folder";
// Type: int
@@ -144,21 +166,25 @@
private static final String RUNTIME_STATE_PENDING_ADD_CELL_X = "launcher.add_cellX";
// Type: int
private static final String RUNTIME_STATE_PENDING_ADD_CELL_Y = "launcher.add_cellY";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_SPAN_X = "launcher.add_spanX";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_spanY";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_COUNT_X = "launcher.add_countX";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_COUNT_Y = "launcher.add_countY";
- // Type: int[]
- private static final String RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS = "launcher.add_occupied_cells";
// Type: boolean
private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME = "launcher.rename_folder";
// Type: long
private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id";
+ // tags for the customization tabs
+ private static final String WIDGETS_TAG = "widgets";
+ private static final String APPLICATIONS_TAG = "applications";
+ private static final String SHORTCUTS_TAG = "shortcuts";
+ private static final String WALLPAPERS_TAG = "wallpapers";
+
+ 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, OVERVIEW,
+ CUSTOMIZE_SPRING_LOADED, ALL_APPS_SPRING_LOADED };
+ private State mState = State.WORKSPACE;
+ private AnimatorSet mStateAnimation;
+
static final int APPWIDGET_HOST_ID = 1024;
private static final Object sLock = new Object();
@@ -176,14 +202,22 @@
private AppWidgetManager mAppWidgetManager;
private LauncherAppWidgetHost mAppWidgetHost;
- private CellLayout.CellInfo mAddItemCellInfo;
- private CellLayout.CellInfo mMenuAddInfo;
- private final int[] mCellCoordinates = new int[2];
+ private int mAddScreen = -1;
+ private int mAddIntersectCellX = -1;
+ private int mAddIntersectCellY = -1;
+ private int[] mAddDropPosition;
+ private int[] mTmpAddItemCellCoordinates = new int[2];
+
private FolderInfo mFolderInfo;
private DeleteZone mDeleteZone;
private HandleView mHandleView;
private AllAppsView mAllAppsGrid;
+ private TabHost mHomeCustomizationDrawer;
+ private boolean mAutoAdvanceRunning = false;
+
+ private AllAppsPagedView mAllAppsPagedView = null;
+ private CustomizePagedView mCustomizePagedView = null;
private Bundle mSavedState;
@@ -200,26 +234,68 @@
private LauncherModel mModel;
private IconCache mIconCache;
+ private boolean mUserPresent = true;
+ private boolean mVisible = false;
+ private boolean mAttached = false;
private static LocaleConfiguration sLocaleConfiguration = null;
private ArrayList<ItemInfo> mDesktopItems = new ArrayList<ItemInfo>();
+
private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
private ImageView mPreviousView;
private ImageView mNextView;
// Hotseats (quick-launch icons next to AllApps)
- private static final int NUM_HOTSEATS = 2;
private String[] mHotseatConfig = null;
private Intent[] mHotseats = null;
private Drawable[] mHotseatIcons = null;
private CharSequence[] mHotseatLabels = null;
+ private Intent mAppMarketIntent = null;
+
+ // Related to the auto-advancing of widgets
+ private final int ADVANCE_MSG = 1;
+ private final int mAdvanceInterval = 20000;
+ private final int mAdvanceStagger = 250;
+ private long mAutoAdvanceSentTime;
+ private long mAutoAdvanceTimeLeft = -1;
+ private HashMap<View, AppWidgetProviderInfo> mWidgetsToAdvance =
+ new HashMap<View, AppWidgetProviderInfo>();
+
+ // Determines how long to wait after a rotation before restoring the screen orientation to
+ // match the sensor state.
+ private final int mRestoreScreenOrientationDelay = 500;
+
+ // External icons saved in case of resource changes, orientation, etc.
+ private static Drawable.ConstantState sGlobalSearchIcon;
+ private static Drawable.ConstantState sVoiceSearchIcon;
+ private static Drawable.ConstantState sAppMarketIcon;
+
+ private CustomizationType getCustomizeFilterForTabTag(String tag) {
+ if (tag.equals(WIDGETS_TAG)) {
+ return CustomizationType.WidgetCustomization;
+ } else if (tag.equals(APPLICATIONS_TAG)) {
+ return CustomizationType.ApplicationCustomization;
+ } else if (tag.equals(WALLPAPERS_TAG)) {
+ return CustomizePagedView.CustomizationType.WallpaperCustomization;
+ } else if (tag.equals(SHORTCUTS_TAG)) {
+ return CustomizePagedView.CustomizationType.ShortcutCustomization;
+ }
+ return CustomizationType.WidgetCustomization;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (LauncherApplication.isInPlaceRotationEnabled()) {
+ // hide the status bar (temporary until we get the status bar design figured out)
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
+ }
+
LauncherApplication app = ((LauncherApplication)getApplication());
mModel = app.setLauncher(this);
mIconCache = app.getIconCache();
@@ -231,14 +307,76 @@
mAppWidgetHost.startListening();
if (PROFILE_STARTUP) {
- android.os.Debug.startMethodTracing("/sdcard/launcher");
+ android.os.Debug.startMethodTracing(
+ Environment.getExternalStorageDirectory() + "/launcher");
}
loadHotseats();
checkForLocaleChange();
- setWallpaperDimension();
-
setContentView(R.layout.launcher);
+ mHomeCustomizationDrawer = (TabHost) findViewById(R.id.customization_drawer);
+ if (mHomeCustomizationDrawer != null) {
+ mHomeCustomizationDrawer.setup();
+
+ // share the same customization workspace across all the tabs
+ mCustomizePagedView = (CustomizePagedView) mInflater.inflate(
+ R.layout.customization_drawer, mHomeCustomizationDrawer, false);
+ TabContentFactory contentFactory = new TabContentFactory() {
+ public View createTabContent(String tag) {
+ return mCustomizePagedView;
+ }
+ };
+
+
+ TextView tabView;
+ TabWidget tabWidget = (TabWidget)
+ mHomeCustomizationDrawer.findViewById(com.android.internal.R.id.tabs);
+
+ tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
+ tabView.setText(getString(R.string.widgets_tab_label));
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec(WIDGETS_TAG)
+ .setIndicator(tabView).setContent(contentFactory));
+ tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
+ tabView.setText(getString(R.string.applications_tab_label));
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec(APPLICATIONS_TAG)
+ .setIndicator(tabView).setContent(contentFactory));
+ tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
+ tabView.setText(getString(R.string.wallpapers_tab_label));
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec(WALLPAPERS_TAG)
+ .setIndicator(tabView).setContent(contentFactory));
+ tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
+ tabView.setText(getString(R.string.shortcuts_tab_label));
+ mHomeCustomizationDrawer.addTab(mHomeCustomizationDrawer.newTabSpec(SHORTCUTS_TAG)
+ .setIndicator(tabView).setContent(contentFactory));
+ mHomeCustomizationDrawer.setOnTabChangedListener(new OnTabChangeListener() {
+ public void onTabChanged(String tabId) {
+ final CustomizePagedView.CustomizationType newType =
+ getCustomizeFilterForTabTag(tabId);
+ if (newType != mCustomizePagedView.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 float alpha = mCustomizePagedView.getAlpha();
+ ValueAnimator alphaAnim = ObjectAnimator.ofFloat(mCustomizePagedView,
+ "alpha", alpha, 0.0f);
+ alphaAnim.setDuration(duration);
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCustomizePagedView.setCustomizationFilter(newType);
+
+ final float alpha = mCustomizePagedView.getAlpha();
+ ValueAnimator alphaAnim = ObjectAnimator.ofFloat(
+ mCustomizePagedView, "alpha", alpha, 1.0f);
+ alphaAnim.setDuration(duration);
+ alphaAnim.start();
+ }
+ });
+ alphaAnim.start();
+ }
+ }
+ });
+ }
setupViews();
registerContentObservers();
@@ -248,6 +386,11 @@
mSavedState = savedInstanceState;
restoreState(mSavedState);
+ // Update customization drawer _after_ restoring the states
+ if (mCustomizePagedView != null) {
+ mCustomizePagedView.update();
+ }
+
if (PROFILE_STARTUP) {
android.os.Debug.stopMethodTracing();
}
@@ -262,6 +405,34 @@
IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
registerReceiver(mCloseSystemDialogsReceiver, filter);
+
+ // If we have a saved version of these external icons, we load them up immediately
+ if (LauncherApplication.isScreenXLarge()) {
+ if (sGlobalSearchIcon != null) {
+ updateGlobalSearchIcon(sGlobalSearchIcon);
+ }
+ if (sVoiceSearchIcon != null) {
+ updateVoiceSearchIcon(sVoiceSearchIcon);
+ }
+ if (sAppMarketIcon != null) {
+ updateAppMarketIcon(sAppMarketIcon);
+ }
+ }
+ }
+
+ @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() {
@@ -306,6 +477,7 @@
final LocaleConfiguration localeConfiguration = sLocaleConfiguration;
new Thread("WriteLocaleConfiguration") {
+ @Override
public void run() {
writeConfiguration(Launcher.this, localeConfiguration);
}
@@ -377,17 +549,6 @@
}
}
- private void setWallpaperDimension() {
- WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE);
-
- Display display = getWindowManager().getDefaultDisplay();
- boolean isPortrait = display.getWidth() < display.getHeight();
-
- final int width = isPortrait ? display.getWidth() : display.getHeight();
- final int height = isPortrait ? display.getHeight() : display.getWidth();
- wpm.suggestDesiredDimensions(width * WALLPAPER_SCREENS_SPAN, height);
- }
-
// Note: This doesn't do all the client-id magic that BrowserProvider does
// in Browser. (http://b/2425179)
private Uri getDefaultBrowserUri() {
@@ -444,7 +605,7 @@
// note: if the user launches this without a default set, she
// will always be taken to the default URL above; this is
// unavoidable as we must specify a valid URL in order for the
- // chooser to appear, and once the user selects something, that
+ // chooser to appear, and once the user selects something, that
// URL is unavoidably sent to the chosen app.
} else {
try {
@@ -454,7 +615,7 @@
// bogus; leave intent=null
}
}
-
+
if (intent == null) {
mHotseats[i] = null;
mHotseatLabels[i] = getText(R.string.activity_not_found);
@@ -462,15 +623,15 @@
}
if (LOGD) {
- Log.d(TAG, "loadHotseats: hotseat " + i
- + " initial intent=["
+ Log.d(TAG, "loadHotseats: hotseat " + i
+ + " initial intent=["
+ intent.toUri(Intent.URI_INTENT_SCHEME)
+ "]");
}
ResolveInfo bestMatch = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
List<ResolveInfo> allMatches = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
- if (LOGD) {
+ if (LOGD) {
Log.d(TAG, "Best match for intent: " + bestMatch);
Log.d(TAG, "All matches: ");
for (ResolveInfo ri : allMatches) {
@@ -479,8 +640,8 @@
}
// did this resolve to a single app, or the resolver?
if (allMatches.size() == 0 || bestMatch == null) {
- // can't find any activity to handle this. let's leave the
- // intent as-is and let Launcher show a toast when it fails
+ // can't find any activity to handle this. let's leave the
+ // intent as-is and let Launcher show a toast when it fails
// to launch.
mHotseats[i] = intent;
@@ -496,7 +657,7 @@
break;
}
}
-
+
if (!found) {
if (LOGD) Log.d(TAG, "Multiple options, no default yet");
// the bestMatch is probably the ResolveActivity, meaning the
@@ -521,8 +682,8 @@
}
if (LOGD) {
- Log.d(TAG, "loadHotseats: hotseat " + i
- + " final intent=["
+ Log.d(TAG, "loadHotseats: hotseat " + i
+ + " final intent=["
+ ((mHotseats[i] == null)
? "null"
: mHotseats[i].toUri(Intent.URI_INTENT_SCHEME))
@@ -543,28 +704,30 @@
// For example, the user would PICK_SHORTCUT for "Music playlist", and we
// launch over to the Music app to actually CREATE_SHORTCUT.
- if (resultCode == RESULT_OK && mAddItemCellInfo != null) {
+ if (resultCode == RESULT_OK && mAddScreen != -1) {
switch (requestCode) {
case REQUEST_PICK_APPLICATION:
- completeAddApplication(this, data, mAddItemCellInfo);
+ completeAddApplication(
+ this, data, mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
break;
case REQUEST_PICK_SHORTCUT:
processShortcut(data);
break;
case REQUEST_CREATE_SHORTCUT:
- completeAddShortcut(data, mAddItemCellInfo);
+ completeAddShortcut(data, mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
break;
case REQUEST_PICK_LIVE_FOLDER:
addLiveFolder(data);
break;
case REQUEST_CREATE_LIVE_FOLDER:
- completeAddLiveFolder(data, mAddItemCellInfo);
+ completeAddLiveFolder(data, mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
break;
case REQUEST_PICK_APPWIDGET:
- addAppWidget(data);
+ addAppWidgetFromPick(data);
break;
case REQUEST_CREATE_APPWIDGET:
- completeAddAppWidget(data, mAddItemCellInfo);
+ int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+ completeAddAppWidget(appWidgetId, mAddScreen);
break;
case REQUEST_PICK_WALLPAPER:
// We just wanted the activity result here so we can clear mWaitingForResult
@@ -591,14 +754,22 @@
mRestoring = false;
mOnResumeNeedsLoad = false;
}
+ // When we resume Launcher, a different Activity might be responsible for the app
+ // market intent, so refresh the icon
+ updateAppMarketIcon();
}
@Override
protected void onPause() {
super.onPause();
+ // Some launcher layouts don't have a previous and next view
+ if (mPreviousView != null) {
+ dismissPreview(mPreviousView);
+ }
+ if (mNextView != null) {
+ dismissPreview(mNextView);
+ }
mPaused = true;
- dismissPreview(mPreviousView);
- dismissPreview(mNextView);
mDragController.cancelDrag();
}
@@ -673,6 +844,22 @@
}
/**
+ * Given the integer (ordinal) value of a State enum instance, convert it to a variable of type
+ * State
+ */
+ private static State intToState(int stateOrdinal) {
+ State state = State.WORKSPACE;
+ final State[] stateValues = State.values();
+ for (int i = 0; i < stateValues.length; i++) {
+ if (stateValues[i].ordinal() == stateOrdinal) {
+ state = stateValues[i];
+ break;
+ }
+ }
+ return state;
+ }
+
+ /**
* Restores the previous state, if it exists.
*
* @param savedState The previous state.
@@ -682,30 +869,25 @@
return;
}
- final boolean allApps = savedState.getBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, false);
- if (allApps) {
+ State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
+
+ if (state == State.ALL_APPS) {
showAllApps(false);
+ } else if (state == State.CUSTOMIZE) {
+ showCustomizationDrawer(false);
}
final int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN, -1);
if (currentScreen > -1) {
- mWorkspace.setCurrentScreen(currentScreen);
+ mWorkspace.setCurrentPage(currentScreen);
}
final int addScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1);
+
if (addScreen > -1) {
- mAddItemCellInfo = new CellLayout.CellInfo();
- final CellLayout.CellInfo addItemCellInfo = mAddItemCellInfo;
- addItemCellInfo.valid = true;
- addItemCellInfo.screen = addScreen;
- addItemCellInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X);
- addItemCellInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y);
- addItemCellInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X);
- addItemCellInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y);
- addItemCellInfo.findVacantCellsFromOccupied(
- savedState.getBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS),
- savedState.getInt(RUNTIME_STATE_PENDING_ADD_COUNT_X),
- savedState.getInt(RUNTIME_STATE_PENDING_ADD_COUNT_Y));
+ mAddScreen = addScreen;
+ mAddIntersectCellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X);
+ mAddIntersectCellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y);
mRestoring = true;
}
@@ -715,13 +897,39 @@
mFolderInfo = mModel.getFolderById(this, sFolders, id);
mRestoring = true;
}
+
+ // Restore the current AllApps drawer tab
+ if (mAllAppsGrid != null && mAllAppsGrid instanceof AllAppsTabbed) {
+ String curTab = savedState.getString("allapps_currentTab");
+ if (curTab != null) {
+ AllAppsTabbed tabhost = (AllAppsTabbed) mAllAppsGrid;
+ tabhost.setCurrentTabByTag(curTab);
+ }
+ int curPage = savedState.getInt("allapps_currentPage", -1);
+ if (curPage > -1) {
+ mAllAppsPagedView.setRestorePage(curPage);
+ }
+ }
+
+ // Restore the current customization drawer tab
+ if (mHomeCustomizationDrawer != null) {
+ String curTab = savedState.getString("customize_currentTab");
+ if (curTab != null) {
+ // We set this directly so that there is no delay before the tab is set
+ mCustomizePagedView.setCustomizationFilter(getCustomizeFilterForTabTag(curTab));
+ mHomeCustomizationDrawer.setCurrentTabByTag(curTab);
+ }
+
+ // Note: currently we do not restore the page for the customization tray because unlike
+ // AllApps, the page content can change drastically
+ }
}
/**
* Finds all the views we need and configure them properly.
*/
private void setupViews() {
- DragController dragController = mDragController;
+ final DragController dragController = mDragController;
DragLayer dragLayer = (DragLayer) findViewById(R.id.drag_layer);
dragLayer.setDragController(dragController);
@@ -730,75 +938,129 @@
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
- ((View) mAllAppsGrid).setFocusable(false);
+ // 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);
+ }
mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
+
final Workspace workspace = mWorkspace;
workspace.setHapticFeedbackEnabled(false);
DeleteZone deleteZone = (DeleteZone) dragLayer.findViewById(R.id.delete_zone);
mDeleteZone = deleteZone;
- mHandleView = (HandleView) findViewById(R.id.all_apps_button);
- mHandleView.setLauncher(this);
- mHandleView.setOnClickListener(this);
- mHandleView.setOnLongClickListener(this);
+ View handleView = findViewById(R.id.all_apps_button);
+ if (handleView != null && handleView instanceof HandleView) {
+ // we don't use handle view in xlarge mode
+ mHandleView = (HandleView)handleView;
+ mHandleView.setLauncher(this);
+ mHandleView.setOnClickListener(this);
+ mHandleView.setOnLongClickListener(this);
+ }
- ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left);
- hotseatLeft.setContentDescription(mHotseatLabels[0]);
- hotseatLeft.setImageDrawable(mHotseatIcons[0]);
- ImageView hotseatRight = (ImageView) findViewById(R.id.hotseat_right);
- hotseatRight.setContentDescription(mHotseatLabels[1]);
- hotseatRight.setImageDrawable(mHotseatIcons[1]);
+ if (mCustomizePagedView != null) {
+ mCustomizePagedView.setLauncher(this);
+ mCustomizePagedView.setDragController(dragController);
+ } else {
+ ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left);
+ hotseatLeft.setContentDescription(mHotseatLabels[0]);
+ hotseatLeft.setImageDrawable(mHotseatIcons[0]);
+ ImageView hotseatRight = (ImageView) findViewById(R.id.hotseat_right);
+ hotseatRight.setContentDescription(mHotseatLabels[1]);
+ hotseatRight.setImageDrawable(mHotseatIcons[1]);
- mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
- mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
+ mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
+ mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
- Drawable previous = mPreviousView.getDrawable();
- Drawable next = mNextView.getDrawable();
- mWorkspace.setIndicators(previous, next);
+ Drawable previous = mPreviousView.getDrawable();
+ Drawable next = mNextView.getDrawable();
+ mWorkspace.setIndicators(previous, next);
- mPreviousView.setHapticFeedbackEnabled(false);
- mPreviousView.setOnLongClickListener(this);
- mNextView.setHapticFeedbackEnabled(false);
- mNextView.setOnLongClickListener(this);
+ mPreviousView.setHapticFeedbackEnabled(false);
+ mPreviousView.setOnLongClickListener(this);
+ mNextView.setHapticFeedbackEnabled(false);
+ mNextView.setOnLongClickListener(this);
+ }
workspace.setOnLongClickListener(this);
workspace.setDragController(dragController);
workspace.setLauncher(this);
+ workspace.setWallpaperDimension();
deleteZone.setLauncher(this);
deleteZone.setDragController(dragController);
- deleteZone.setHandle(findViewById(R.id.all_apps_button_cluster));
+
+ final View allAppsButton = findViewById(R.id.all_apps_button);
+ final View divider = findViewById(R.id.divider);
+ final View configureButton = findViewById(R.id.configure_button);
+
+ if (LauncherApplication.isScreenXLarge()) {
+ deleteZone.setOverlappingViews(new View[] { allAppsButton, divider, configureButton });
+ } else {
+ deleteZone.setOverlappingView(findViewById(R.id.all_apps_button_cluster));
+ }
+ dragController.addDragListener(deleteZone);
+
+ DeleteZone allAppsDeleteZone = (DeleteZone) findViewById(R.id.all_apps_delete_zone);
+ if (allAppsDeleteZone != null) {
+ allAppsDeleteZone.setLauncher(this);
+ allAppsDeleteZone.setDragController(dragController);
+ allAppsDeleteZone.setDragAndDropEnabled(false);
+ dragController.addDragListener(allAppsDeleteZone);
+ dragController.addDropTarget(allAppsDeleteZone);
+ }
+
+ ApplicationInfoDropTarget allAppsInfoTarget = (ApplicationInfoDropTarget)
+ findViewById(R.id.all_apps_info_target);
+ if (allAppsInfoTarget != null) {
+ allAppsInfoTarget.setLauncher(this);
+ dragController.addDragListener(allAppsInfoTarget);
+ allAppsInfoTarget.setDragAndDropEnabled(false);
+ View marketButton = findViewById(R.id.market_button);
+ if (marketButton != null) {
+ allAppsInfoTarget.setOverlappingView(marketButton);
+ }
+ }
dragController.setDragScoller(workspace);
- dragController.setDragListener(deleteZone);
dragController.setScrollView(dragLayer);
dragController.setMoveTarget(workspace);
// The order here is bottom to top.
dragController.addDropTarget(workspace);
dragController.addDropTarget(deleteZone);
+ if (allAppsInfoTarget != null) {
+ dragController.addDropTarget(allAppsInfoTarget);
+ }
+ if (allAppsDeleteZone != null) {
+ dragController.addDropTarget(allAppsDeleteZone);
+ }
}
@SuppressWarnings({"UnusedDeclaration"})
public void previousScreen(View v) {
- if (!isAllAppsVisible()) {
+ if (mState != State.ALL_APPS) {
mWorkspace.scrollLeft();
}
}
@SuppressWarnings({"UnusedDeclaration"})
public void nextScreen(View v) {
- if (!isAllAppsVisible()) {
+ if (mState != State.ALL_APPS) {
mWorkspace.scrollRight();
}
}
@SuppressWarnings({"UnusedDeclaration"})
public void launchHotSeat(View v) {
- if (isAllAppsVisible()) return;
+ if (mState == State.ALL_APPS) return;
int index = -1;
if (v.getId() == R.id.hotseat_left) {
@@ -810,14 +1072,13 @@
// reload these every tap; you never know when they might change
loadHotseats();
if (index >= 0 && index < mHotseats.length && mHotseats[index] != null) {
- Intent intent = mHotseats[index];
startActivitySafely(
mHotseats[index],
"hotseat"
);
}
}
-
+
/**
* Creates a view representing a shortcut.
*
@@ -827,7 +1088,7 @@
*/
View createShortcut(ShortcutInfo info) {
return createShortcut(R.layout.application,
- (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info);
+ (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
}
/**
@@ -840,15 +1101,9 @@
* @return A View inflated from layoutResId.
*/
View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
- TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false);
-
- favorite.setCompoundDrawablesWithIntrinsicBounds(null,
- new FastBitmapDrawable(info.getIcon(mIconCache)),
- null, null);
- favorite.setText(info.title);
- favorite.setTag(info);
+ BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
+ favorite.applyFromShortcutInfo(info, mIconCache);
favorite.setOnClickListener(this);
-
return favorite;
}
@@ -858,9 +1113,15 @@
* @param data The intent describing the application.
* @param cellInfo The position on screen where to create the shortcut.
*/
- void completeAddApplication(Context context, Intent data, CellLayout.CellInfo cellInfo) {
- cellInfo.screen = mWorkspace.getCurrentScreen();
- if (!findSingleSlot(cellInfo)) return;
+ void completeAddApplication(Context context, Intent data, int screen,
+ int intersectCellX, int intersectCellY) {
+ final int[] cellXY = mTmpAddItemCellCoordinates;
+ final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
+
+ if (!layout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectCellX, intersectCellY)) {
+ showOutOfSpaceMessage();
+ return;
+ }
final ShortcutInfo info = mModel.getShortcutInfo(context.getPackageManager(),
data, context);
@@ -869,7 +1130,8 @@
info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
info.container = ItemInfo.NO_ID;
- mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked());
+ mWorkspace.addApplicationShortcut(info, screen, cellXY[0], cellXY[1],
+ isWorkspaceLocked(), mAddIntersectCellX, mAddIntersectCellY);
} else {
Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data);
}
@@ -881,53 +1143,96 @@
* @param data The intent describing the shortcut.
* @param cellInfo The position on screen where to create the shortcut.
*/
- private void completeAddShortcut(Intent data, CellLayout.CellInfo cellInfo) {
- cellInfo.screen = mWorkspace.getCurrentScreen();
- if (!findSingleSlot(cellInfo)) return;
+ private void completeAddShortcut(Intent data, int screen,
+ int intersectCellX, int intersectCellY) {
+ final int[] cellXY = mTmpAddItemCellCoordinates;
+ final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
- final ShortcutInfo info = mModel.addShortcut(this, data, cellInfo, false);
+ int[] touchXY = null;
+ if (mAddDropPosition != null && mAddDropPosition[0] > -1 && mAddDropPosition[1] > -1) {
+ touchXY = mAddDropPosition;
+ }
+ boolean foundCellSpan = false;
+ if (touchXY != null) {
+ // when dragging and dropping, just find the closest free spot
+ CellLayout screenLayout = (CellLayout) mWorkspace.getChildAt(screen);
+ int[] result = screenLayout.findNearestVacantArea(
+ touchXY[0], touchXY[1], 1, 1, cellXY);
+ foundCellSpan = (result != null);
+ } else {
+ foundCellSpan = layout.findCellForSpanThatIntersects(
+ cellXY, 1, 1, intersectCellX, intersectCellY);
+ }
+
+ if (!foundCellSpan) {
+ showOutOfSpaceMessage();
+ return;
+ }
+
+ final ShortcutInfo info = mModel.addShortcut(
+ this, data, screen, cellXY[0], cellXY[1], false);
if (!mRestoring) {
final View view = createShortcut(info);
- mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1,
- isWorkspaceLocked());
+ mWorkspace.addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked());
}
}
-
/**
* Add a widget to the workspace.
*
- * @param data The intent describing the appWidgetId.
+ * @param appWidgetId The app widget id
* @param cellInfo The position on screen where to create the widget.
*/
- private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
- Bundle extras = data.getExtras();
- int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
-
- if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
-
+ private void completeAddAppWidget(int appWidgetId, int screen) {
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
// Calculate the grid spans needed to fit this widget
- CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
- int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight);
+ CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
+ int[] spanXY = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight, null);
// Try finding open space on Launcher screen
- final int[] xy = mCellCoordinates;
- if (!findSlot(cellInfo, xy, spans[0], spans[1])) {
+ // We have saved the position to which the widget was dragged-- this really only matters
+ // if we are placing widgets on a "spring-loaded" screen
+ final int[] cellXY = mTmpAddItemCellCoordinates;
+
+ // For now, we don't save the coordinate where we dropped the icon because we're not
+ // supporting spring-loaded mini-screens; however, leaving the ability to directly place
+ // a widget on the home screen in case we want to add it in the future
+ int[] touchXY = null;
+ if (mAddDropPosition != null && mAddDropPosition[0] > -1 && mAddDropPosition[1] > -1) {
+ touchXY = mAddDropPosition;
+ }
+ boolean foundCellSpan = false;
+ if (touchXY != null) {
+ // when dragging and dropping, just find the closest free spot
+ CellLayout screenLayout = (CellLayout) mWorkspace.getChildAt(screen);
+ int[] result = screenLayout.findNearestVacantArea(
+ touchXY[0], touchXY[1], spanXY[0], spanXY[1], cellXY);
+ foundCellSpan = (result != null);
+ } else {
+ // if we long pressed on an empty cell to bring up a menu,
+ // make sure we intersect the empty cell
+ // if mAddIntersectCellX/Y are -1 (e.g. we used menu -> add) then
+ // findCellForSpanThatIntersects will just ignore them
+ foundCellSpan = layout.findCellForSpanThatIntersects(cellXY, spanXY[0], spanXY[1],
+ mAddIntersectCellX, mAddIntersectCellY);
+ }
+
+ if (!foundCellSpan) {
if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+ showOutOfSpaceMessage();
return;
}
// Build Launcher-specific widget info and save to database
LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId);
- launcherInfo.spanX = spans[0];
- launcherInfo.spanY = spans[1];
+ launcherInfo.spanX = spanXY[0];
+ launcherInfo.spanY = spanXY[1];
LauncherModel.addItemToDatabase(this, launcherInfo,
LauncherSettings.Favorites.CONTAINER_DESKTOP,
- mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
+ screen, cellXY[0], cellXY[1], false);
if (!mRestoring) {
mDesktopItems.add(launcherInfo);
@@ -938,20 +1243,140 @@
launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
launcherInfo.hostView.setTag(launcherInfo);
- mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1],
+ mWorkspace.addInScreen(launcherInfo.hostView, screen, cellXY[0], cellXY[1],
launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
+
+ addWidgetToAutoAdvanceIfNeeded(launcherInfo.hostView, appWidgetInfo);
+ }
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+ mUserPresent = false;
+ updateRunning();
+ } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
+ mUserPresent = true;
+ updateRunning();
+ }
+ }
+ };
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ // Listen for broadcasts related to user-presence
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_USER_PRESENT);
+ registerReceiver(mReceiver, filter);
+
+ mAttached = true;
+ mVisible = true;
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mVisible = false;
+
+ if (mAttached) {
+ unregisterReceiver(mReceiver);
+ mAttached = false;
+ }
+ updateRunning();
+ }
+
+ public void onWindowVisibilityChanged(int visibility) {
+ mVisible = visibility == View.VISIBLE;
+ updateRunning();
+ }
+
+ private void sendAdvanceMessage(long delay) {
+ mHandler.removeMessages(ADVANCE_MSG);
+ Message msg = mHandler.obtainMessage(ADVANCE_MSG);
+ mHandler.sendMessageDelayed(msg, delay);
+ mAutoAdvanceSentTime = System.currentTimeMillis();
+ }
+
+ private void updateRunning() {
+ boolean autoAdvanceRunning = mVisible && mUserPresent && !mWidgetsToAdvance.isEmpty();
+ if (autoAdvanceRunning != mAutoAdvanceRunning) {
+ mAutoAdvanceRunning = autoAdvanceRunning;
+ if (autoAdvanceRunning) {
+ long delay = mAutoAdvanceTimeLeft == -1 ? mAdvanceInterval : mAutoAdvanceTimeLeft;
+ sendAdvanceMessage(delay);
+ } else {
+ if (!mWidgetsToAdvance.isEmpty()) {
+ mAutoAdvanceTimeLeft = Math.max(0, mAdvanceInterval -
+ (System.currentTimeMillis() - mAutoAdvanceSentTime));
+ }
+ mHandler.removeMessages(ADVANCE_MSG);
+ mHandler.removeMessages(0); // Remove messages sent using postDelayed()
+ }
+ }
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == ADVANCE_MSG) {
+ int i = 0;
+ for (View key: mWidgetsToAdvance.keySet()) {
+ final View v = key.findViewById(mWidgetsToAdvance.get(key).autoAdvanceViewId);
+ final int delay = mAdvanceStagger * i;
+ if (v instanceof Advanceable) {
+ postDelayed(new Runnable() {
+ public void run() {
+ ((Advanceable) v).advance();
+ }
+ }, delay);
+ }
+ i++;
+ }
+ sendAdvanceMessage(mAdvanceInterval);
+ }
+ }
+ };
+
+ void addWidgetToAutoAdvanceIfNeeded(View hostView, AppWidgetProviderInfo appWidgetInfo) {
+ if (appWidgetInfo.autoAdvanceViewId == -1) return;
+ View v = hostView.findViewById(appWidgetInfo.autoAdvanceViewId);
+ if (v instanceof Advanceable) {
+ mWidgetsToAdvance.put(hostView, appWidgetInfo);
+ ((Advanceable) v).fyiWillBeAdvancedByHostKThx();
+ updateRunning();
+ }
+ }
+
+ void removeWidgetToAutoAdvance(View hostView) {
+ if (mWidgetsToAdvance.containsKey(hostView)) {
+ mWidgetsToAdvance.remove(hostView);
+ updateRunning();
}
}
public void removeAppWidget(LauncherAppWidgetInfo launcherInfo) {
mDesktopItems.remove(launcherInfo);
+ removeWidgetToAutoAdvance(launcherInfo.hostView);
launcherInfo.hostView = null;
}
+ void showOutOfSpaceMessage() {
+ Toast.makeText(this, getString(R.string.out_of_space), Toast.LENGTH_SHORT).show();
+ }
+
public LauncherAppWidgetHost getAppWidgetHost() {
return mAppWidgetHost;
}
+ public LauncherModel getModel() {
+ return mModel;
+ }
+
void closeSystemDialogs() {
getWindow().closeAllPanels();
@@ -984,11 +1409,19 @@
boolean alreadyOnHome = ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
!= Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
- boolean allAppsVisible = isAllAppsVisible();
- if (!mWorkspace.isDefaultScreenShowing()) {
- mWorkspace.moveToDefaultScreen(alreadyOnHome && !allAppsVisible);
+
+ // in all these cases, only animate if we're already on home
+ if (LauncherApplication.isScreenXLarge()) {
+ mWorkspace.unshrink(alreadyOnHome);
}
- closeAllApps(alreadyOnHome && allAppsVisible);
+ if (!mWorkspace.isDefaultPageShowing()) {
+ // on the phone, we don't animate the change to the workspace if all apps is visible
+ boolean animate = alreadyOnHome &&
+ (LauncherApplication.isScreenXLarge() || mState != State.ALL_APPS);
+ mWorkspace.moveToDefaultScreen(animate);
+ if (!animate) mWorkspace.updateWallpaperOffsetImmediately();
+ }
+ showWorkspace(alreadyOnHome);
final View v = getWindow().peekDecorView();
if (v != null && v.getWindowToken() != null) {
@@ -1007,7 +1440,7 @@
@Override
protected void onSaveInstanceState(Bundle outState) {
- outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getCurrentScreen());
+ outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getCurrentPage());
final ArrayList<Folder> folders = mWorkspace.getOpenFolders();
if (folders.size() > 0) {
@@ -1022,30 +1455,36 @@
super.onSaveInstanceState(outState);
}
- // TODO should not do this if the drawer is currently closing.
- if (isAllAppsVisible()) {
- outState.putBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, true);
- }
+ outState.putInt(RUNTIME_STATE, mState.ordinal());
- if (mAddItemCellInfo != null && mAddItemCellInfo.valid && mWaitingForResult) {
- final CellLayout.CellInfo addItemCellInfo = mAddItemCellInfo;
- final CellLayout layout = (CellLayout) mWorkspace.getChildAt(addItemCellInfo.screen);
-
- outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, addItemCellInfo.screen);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_X, addItemCellInfo.cellX);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_Y, addItemCellInfo.cellY);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_X, addItemCellInfo.spanX);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y, addItemCellInfo.spanY);
- outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_X, layout.getCountX());
- outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_Y, layout.getCountY());
- outState.putBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS,
- layout.getOccupiedCells());
+ if (mAddScreen > -1 && mWaitingForResult) {
+ outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, mAddScreen);
+ outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_X, mAddIntersectCellX);
+ outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_Y, mAddIntersectCellY);
}
if (mFolderInfo != null && mWaitingForResult) {
outState.putBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, true);
outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id);
}
+
+ // Save the current AllApps drawer tab
+ if (mAllAppsGrid != null && mAllAppsGrid instanceof AllAppsTabbed) {
+ AllAppsTabbed tabhost = (AllAppsTabbed) mAllAppsGrid;
+ String currentTabTag = tabhost.getCurrentTabTag();
+ if (currentTabTag != null) {
+ outState.putString("allapps_currentTab", currentTabTag);
+ outState.putInt("allapps_currentPage", mAllAppsPagedView.getCurrentPage());
+ }
+ }
+
+ // Save the current customization drawer tab
+ if (mHomeCustomizationDrawer != null) {
+ String currentTabTag = mHomeCustomizationDrawer.getCurrentTabTag();
+ if (currentTabTag != null) {
+ outState.putString("customize_currentTab", currentTabTag);
+ }
+ }
}
@Override
@@ -1057,6 +1496,9 @@
} catch (NullPointerException ex) {
Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
}
+ mAppWidgetHost = null;
+
+ mWidgetsToAdvance.clear();
TextKeyListener.getInstance().release();
@@ -1065,11 +1507,23 @@
unbindDesktopItems();
getContentResolver().unregisterContentObserver(mWidgetObserver);
-
- dismissPreview(mPreviousView);
- dismissPreview(mNextView);
+
+ // Some launcher layouts don't have a previous and next view
+ if (mPreviousView != null) {
+ dismissPreview(mPreviousView);
+ }
+ if (mNextView != null) {
+ dismissPreview(mNextView);
+ }
unregisterReceiver(mCloseSystemDialogsReceiver);
+
+ ((ViewGroup) mWorkspace.getParent()).removeAllViews();
+ mWorkspace.removeAllViews();
+ mWorkspace = null;
+ mDragController = null;
+
+ ValueAnimator.clearAllAnimations();
}
@Override
@@ -1082,7 +1536,7 @@
public void startSearch(String initialQuery, boolean selectInitialQuery,
Bundle appSearchData, boolean globalSearch) {
- closeAllApps(true);
+ showWorkspace(true);
if (initialQuery == null) {
// Use any text typed in the launcher as the initial query
@@ -1141,19 +1595,19 @@
// If all apps is animating, don't show the menu, because we don't know
// which one to show.
- if (mAllAppsGrid.isVisible() && !mAllAppsGrid.isOpaque()) {
+ if (mAllAppsGrid.isAnimating()) {
return false;
}
// Only show the add and wallpaper options when we're not in all apps.
- boolean visible = !mAllAppsGrid.isOpaque();
+ 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) {
- mMenuAddInfo = mWorkspace.findAllVacantCells(null);
- menu.setGroupEnabled(MENU_GROUP_ADD, mMenuAddInfo != null && mMenuAddInfo.valid);
+ CellLayout layout = (CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
+ menu.setGroupEnabled(MENU_GROUP_ADD, layout.existsEmptyCell());
}
return true;
@@ -1198,17 +1652,47 @@
}
private void addItems() {
- closeAllApps(true);
- showAddDialog(mMenuAddInfo);
+ if (LauncherApplication.isScreenXLarge()) {
+ // Animate the widget chooser up from the bottom of the screen
+ if (mState != State.CUSTOMIZE) {
+ showCustomizationDrawer(true);
+ }
+ } else {
+ showWorkspace(true);
+ showAddDialog(-1, -1);
+ }
+ }
+
+ private void resetAddInfo() {
+ mAddScreen = -1;
+ mAddIntersectCellX = -1;
+ mAddIntersectCellY = -1;
+ mAddDropPosition = null;
+ }
+
+ void addAppWidgetFromDrop(PendingAddWidgetInfo info, int screen, int[] position) {
+ resetAddInfo();
+ mAddScreen = screen;
+ mAddDropPosition = position;
+
+ int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
+ AppWidgetManager.getInstance(this).bindAppWidgetId(appWidgetId, info.componentName);
+ addAppWidgetImpl(appWidgetId, info);
}
private void manageApps() {
startActivity(new Intent(android.provider.Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS));
}
- void addAppWidget(Intent data) {
+ void addAppWidgetFromPick(Intent data) {
// TODO: catch bad widget exception when sent
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+ // TODO: Is this log message meaningful?
+ if (LOGD) Log.d(TAG, "dumping extras content=" + data.getExtras());
+ addAppWidgetImpl(appWidgetId, null);
+ }
+
+ void addAppWidgetImpl(int appWidgetId, PendingAddWidgetInfo info) {
AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
if (appWidget.configure != null) {
@@ -1216,14 +1700,53 @@
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.setComponent(appWidget.configure);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ if (info != null) {
+ if (info.mimeType != null && !info.mimeType.isEmpty()) {
+ intent.putExtra(
+ InstallWidgetReceiver.EXTRA_APPWIDGET_CONFIGURATION_DATA_MIME_TYPE,
+ info.mimeType);
+
+ final String mimeType = info.mimeType;
+ final ClipData clipData = (ClipData) info.configurationData;
+ final ClipDescription clipDesc = clipData.getDescription();
+ for (int i = 0; i < clipDesc.getMimeTypeCount(); ++i) {
+ if (clipDesc.getMimeType(i).equals(mimeType)) {
+ final ClipData.Item item = clipData.getItemAt(i);
+ final CharSequence stringData = item.getText();
+ final Uri uriData = item.getUri();
+ final Intent intentData = item.getIntent();
+ final String key =
+ InstallWidgetReceiver.EXTRA_APPWIDGET_CONFIGURATION_DATA;
+ if (uriData != null) {
+ intent.putExtra(key, uriData);
+ } else if (intentData != null) {
+ intent.putExtra(key, intentData);
+ } else if (stringData != null) {
+ intent.putExtra(key, stringData);
+ }
+ break;
+ }
+ }
+ }
+ }
startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
} else {
// Otherwise just add it
- onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
+ completeAddAppWidget(appWidgetId, mAddScreen);
}
}
+ void processShortcutFromDrop(ComponentName componentName, int screen, int[] position) {
+ resetAddInfo();
+ mAddScreen = screen;
+ mAddDropPosition = position;
+
+ Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+ createShortcutIntent.setComponent(componentName);
+ processShortcut(createShortcutIntent);
+ }
+
void processShortcut(Intent intent) {
// Handle case where user selected "Applications"
String applicationName = getResources().getString(R.string.group_applications);
@@ -1242,59 +1765,81 @@
}
}
- void addLiveFolder(Intent intent) {
+ void processWallpaper(Intent intent) {
+ 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();
+ addFolder(mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
} else {
startActivityForResultSafely(intent, REQUEST_CREATE_LIVE_FOLDER);
}
}
- void addFolder() {
+ void addFolder(int screen, int intersectCellX, int intersectCellY) {
UserFolderInfo folderInfo = new UserFolderInfo();
folderInfo.title = getText(R.string.folder_name);
- CellLayout.CellInfo cellInfo = mAddItemCellInfo;
- cellInfo.screen = mWorkspace.getCurrentScreen();
- if (!findSingleSlot(cellInfo)) return;
+ final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
+ final int[] cellXY = mTmpAddItemCellCoordinates;
+ if (!layout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectCellX, intersectCellY)) {
+ showOutOfSpaceMessage();
+ return;
+ }
// Update the model
LauncherModel.addItemToDatabase(this, folderInfo,
LauncherSettings.Favorites.CONTAINER_DESKTOP,
- mWorkspace.getCurrentScreen(), cellInfo.cellX, cellInfo.cellY, false);
+ screen, cellXY[0], cellXY[1], false);
sFolders.put(folderInfo.id, folderInfo);
// Create the view
FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
- (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), folderInfo);
- mWorkspace.addInCurrentScreen(newFolder,
- cellInfo.cellX, cellInfo.cellY, 1, 1, isWorkspaceLocked());
+ (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()),
+ folderInfo, mIconCache);
+ mWorkspace.addInScreen(newFolder, screen, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked());
}
void removeFolder(FolderInfo folder) {
sFolders.remove(folder.id);
}
- private void completeAddLiveFolder(Intent data, CellLayout.CellInfo cellInfo) {
- cellInfo.screen = mWorkspace.getCurrentScreen();
- if (!findSingleSlot(cellInfo)) return;
+ 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, cellInfo, false);
+ 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.getCurrentScreen()), info);
- mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1,
- isWorkspaceLocked());
+ (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
+ mWorkspace.addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked());
}
}
static LiveFolderInfo addLiveFolder(Context context, Intent data,
- CellLayout.CellInfo cellInfo, boolean notify) {
+ 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);
@@ -1330,35 +1875,12 @@
LiveFolders.DISPLAY_MODE_GRID);
LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
- cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
+ screen, cellX, cellY, notify);
sFolders.put(info.id, info);
return info;
}
- private boolean findSingleSlot(CellLayout.CellInfo cellInfo) {
- final int[] xy = new int[2];
- if (findSlot(cellInfo, xy, 1, 1)) {
- cellInfo.cellX = xy[0];
- cellInfo.cellY = xy[1];
- return true;
- }
- return false;
- }
-
- private boolean findSlot(CellLayout.CellInfo cellInfo, int[] xy, int spanX, int spanY) {
- if (!cellInfo.findCellForSpan(xy, spanX, spanY)) {
- boolean[] occupied = mSavedState != null ?
- mSavedState.getBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS) : null;
- cellInfo = mWorkspace.findAllVacantCells(occupied);
- if (!cellInfo.findCellForSpan(xy, spanX, spanY)) {
- Toast.makeText(this, getString(R.string.out_of_space), Toast.LENGTH_SHORT).show();
- return false;
- }
- }
- return true;
- }
-
private void showNotifications() {
final StatusBarManager statusBar = (StatusBarManager) getSystemService(STATUS_BAR_SERVICE);
if (statusBar != null) {
@@ -1367,7 +1889,7 @@
}
private void startWallpaper() {
- closeAllApps(true);
+ showWorkspace(true);
final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
Intent chooser = Intent.createChooser(pickWallpaper,
getText(R.string.chooser_wallpaper));
@@ -1420,13 +1942,16 @@
@Override
public void onBackPressed() {
- if (isAllAppsVisible()) {
- closeAllApps(true);
+ if (mState == State.ALL_APPS || mState == State.CUSTOMIZE) {
+ showWorkspace(true);
} else {
closeFolder();
}
- dismissPreview(mPreviousView);
- dismissPreview(mNextView);
+ // Some launcher layouts don't have a previous and next view
+ if (mPreviousView != null) {
+ dismissPreview(mPreviousView);
+ dismissPreview(mNextView);
+ }
}
private void closeFolder() {
@@ -1440,7 +1965,8 @@
folder.getInfo().opened = false;
ViewGroup parent = (ViewGroup) folder.getParent();
if (parent != null) {
- parent.removeView(folder);
+ CellLayout cl = (CellLayout) parent;
+ cl.removeViewWithoutMarkingCells(folder);
if (folder instanceof DropTarget) {
// Live folders aren't DropTargets.
mDragController.removeDropTarget((DropTarget)folder);
@@ -1464,6 +1990,7 @@
for (ItemInfo item: mDesktopItems) {
item.unbind();
}
+ mDesktopItems.clear();
}
/**
@@ -1484,14 +2011,95 @@
} else if (tag instanceof FolderInfo) {
handleFolderClick((FolderInfo) tag);
} else if (v == mHandleView) {
- if (isAllAppsVisible()) {
- closeAllApps(true);
+ if (mState == State.ALL_APPS) {
+ showWorkspace(true);
} else {
showAllApps(true);
}
}
}
+ public boolean onTouch(View v, MotionEvent event) {
+ // this is an intercepted event being forwarded from mWorkspace;
+ // clicking anywhere on the workspace causes the customization drawer to slide down
+ showWorkspace(true);
+ return false;
+ }
+
+ /**
+ * Event handler for the search button
+ *
+ * @param v The view that was clicked.
+ */
+ public void onClickSearchButton(View v) {
+ startSearch(null, false, null, true);
+ // Use a custom animation for launching search
+ overridePendingTransition(R.anim.fade_in_fast, R.anim.fade_out_fast);
+ }
+
+ /**
+ * Event handler for the voice button
+ *
+ * @param v The view that was clicked.
+ */
+ public void onClickVoiceButton(View v) {
+ startVoiceSearch();
+ }
+
+ private void startVoiceSearch() {
+ Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+
+ /**
+ * Event handler for the "gear" button that appears on the home screen, which
+ * enters home screen customization mode.
+ *
+ * @param v The view that was clicked.
+ */
+ public void onClickConfigureButton(View v) {
+ addItems();
+ }
+
+ /**
+ * Event handler for the "grid" button that appears on the home screen, which
+ * enters all apps mode.
+ *
+ * @param v The view that was clicked.
+ */
+ public void onClickAllAppsButton(View v) {
+ showAllApps(true);
+ }
+
+ public void onClickAppMarketButton(View v) {
+ if (mAppMarketIntent != null) {
+ startActivitySafely(mAppMarketIntent, "app market");
+ }
+ }
+
+ void startApplicationDetailsActivity(ComponentName componentName) {
+ String packageName = componentName.getPackageName();
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", packageName, null));
+ startActivity(intent);
+ }
+
+ void startApplicationUninstallActivity(ApplicationInfo appInfo) {
+ if ((appInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) == 0) {
+ // System applications cannot be installed. For now, show a toast explaining that.
+ // We may give them the option of disabling apps this way.
+ int messageId = R.string.uninstall_system_app_text;
+ Toast.makeText(this, messageId, Toast.LENGTH_SHORT).show();
+ } else {
+ String packageName = appInfo.componentName.getPackageName();
+ String className = appInfo.componentName.getClassName();
+ Intent intent = new Intent(
+ Intent.ACTION_DELETE, Uri.fromParts("package", packageName, className));
+ startActivity(intent);
+ }
+ }
+
void startActivitySafely(Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
@@ -1507,7 +2115,7 @@
+ "tag="+ tag + " intent=" + intent, e);
}
}
-
+
void startActivityForResultSafely(Intent intent, int requestCode) {
try {
startActivityForResult(intent, requestCode);
@@ -1532,10 +2140,10 @@
Folder openFolder = mWorkspace.getFolderForTag(folderInfo);
int folderScreen;
if (openFolder != null) {
- folderScreen = mWorkspace.getScreenForView(openFolder);
+ folderScreen = mWorkspace.getPageForView(openFolder);
// .. and close it
closeFolder(openFolder);
- if (folderScreen != mWorkspace.getCurrentScreen()) {
+ if (folderScreen != mWorkspace.getCurrentPage()) {
// Close any folder open on the current screen
closeFolder();
// Pull the folder onto this screen
@@ -1546,13 +2154,13 @@
}
/**
- * Opens the user fodler described by the specified tag. The opening of the folder
+ * Opens the user folder described by the specified tag. The opening of the folder
* is animated relative to the specified View. If the View is null, no animation
* is played.
*
* @param folderInfo The FolderInfo describing the folder to open.
*/
- private void openFolder(FolderInfo folderInfo) {
+ public void openFolder(FolderInfo folderInfo) {
Folder openFolder;
if (folderInfo instanceof UserFolderInfo) {
@@ -1569,28 +2177,29 @@
openFolder.bind(folderInfo);
folderInfo.opened = true;
- mWorkspace.addInScreen(openFolder, folderInfo.screen, 0, 0, 4, 4);
+ mWorkspace.addInFullScreen(openFolder, folderInfo.screen);
+
openFolder.onOpen();
}
public boolean onLongClick(View v) {
switch (v.getId()) {
case R.id.previous_screen:
- if (!isAllAppsVisible()) {
+ if (mState != State.ALL_APPS) {
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
showPreviews(v);
}
return true;
case R.id.next_screen:
- if (!isAllAppsVisible()) {
+ if (mState != State.ALL_APPS) {
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
showPreviews(v);
}
return true;
case R.id.all_apps_button:
- if (!isAllAppsVisible()) {
+ if (mState != State.ALL_APPS) {
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
showPreviews(v);
@@ -1606,28 +2215,35 @@
v = (View) v.getParent();
}
- CellLayout.CellInfo cellInfo = (CellLayout.CellInfo) v.getTag();
+ resetAddInfo();
+ CellLayout.CellInfo longClickCellInfo = (CellLayout.CellInfo) v.getTag();
// This happens when long clicking an item with the dpad/trackball
- if (cellInfo == null) {
+ if (longClickCellInfo == null || !longClickCellInfo.valid) {
return true;
}
- if (mWorkspace.allowLongPress()) {
- if (cellInfo.cell == null) {
- if (cellInfo.valid) {
- // User long pressed on empty space
- mWorkspace.setAllowLongPress(false);
- mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- showAddDialog(cellInfo);
+ final View itemUnderLongClick = longClickCellInfo.cell;
+
+ if (mWorkspace.allowLongPress() && !mDragController.isDragging()) {
+ if (itemUnderLongClick == null) {
+ // User long pressed on empty space
+ mWorkspace.setAllowLongPress(false);
+ mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ if (LauncherApplication.isScreenXLarge()) {
+ addItems();
+ } else {
+ showAddDialog(longClickCellInfo.cellX, longClickCellInfo.cellY);
}
} else {
- if (!(cellInfo.cell instanceof Folder)) {
+ if (!(itemUnderLongClick instanceof Folder)) {
// User long pressed on an item
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- mWorkspace.startDrag(cellInfo);
+ mAddIntersectCellX = longClickCellInfo.cellX;
+ mAddIntersectCellY = longClickCellInfo.cellY;
+ mWorkspace.startDrag(longClickCellInfo);
}
}
}
@@ -1667,9 +2283,9 @@
final Workspace workspace = mWorkspace;
CellLayout cell = ((CellLayout) workspace.getChildAt(start));
-
+
float max = workspace.getChildCount();
-
+
final Rect r = new Rect();
resources.getDrawable(R.drawable.preview_background).getPadding(r);
int extraW = (int) ((r.left + r.right) * max);
@@ -1707,7 +2323,7 @@
final Canvas c = new Canvas(bitmap);
c.scale(scale, scale);
c.translate(-cell.getLeftPadding(), -cell.getTopPadding());
- cell.dispatchDraw(c);
+ cell.drawChildren(c);
image.setBackgroundDrawable(resources.getDrawable(R.drawable.preview_background));
image.setImageBitmap(bitmap);
@@ -1715,12 +2331,12 @@
image.setOnClickListener(handler);
image.setOnFocusChangeListener(handler);
image.setFocusable(true);
- if (i == mWorkspace.getCurrentScreen()) image.requestFocus();
+ if (i == mWorkspace.getCurrentPage()) image.requestFocus();
preview.addView(image,
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- bitmaps.add(bitmap);
+ bitmaps.add(bitmap);
}
final PopupWindow p = new PopupWindow(this);
@@ -1741,7 +2357,7 @@
anchor.setTag(p);
anchor.setTag(R.id.workspace, preview);
- anchor.setTag(R.id.icon, bitmaps);
+ anchor.setTag(R.id.icon, bitmaps);
}
class PreviewTouchHandler implements View.OnClickListener, Runnable, View.OnFocusChangeListener {
@@ -1752,17 +2368,17 @@
}
public void onClick(View v) {
- mWorkspace.snapToScreen((Integer) v.getTag());
+ mWorkspace.snapToPage((Integer) v.getTag());
v.post(this);
}
public void run() {
- dismissPreview(mAnchor);
+ dismissPreview(mAnchor);
}
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
- mWorkspace.snapToScreen((Integer) v.getTag());
+ mWorkspace.snapToPage((Integer) v.getTag());
}
}
}
@@ -1805,13 +2421,17 @@
showDialog(DIALOG_RENAME_FOLDER);
}
- private void showAddDialog(CellLayout.CellInfo cellInfo) {
- mAddItemCellInfo = cellInfo;
+ private void showAddDialog(int intersectX, int intersectY) {
+ resetAddInfo();
+ mAddIntersectCellX = intersectX;
+ mAddIntersectCellY = intersectY;
+ mAddScreen = mWorkspace.getCurrentPage();
mWaitingForResult = true;
showDialog(DIALOG_CREATE_SHORTCUT);
}
private void pickShortcut() {
+ // Insert extra item to handle picking application
Bundle bundle = new Bundle();
ArrayList<String> shortcutNames = new ArrayList<String>();
@@ -1913,24 +2533,456 @@
// Now a part of LauncherModel.Callbacks. Used to reorder loading steps.
public boolean isAllAppsVisible() {
- return (mAllAppsGrid != null) ? mAllAppsGrid.isVisible() : false;
+ return mState == State.ALL_APPS;
}
// AllAppsView.Watcher
public void zoomed(float zoom) {
- if (zoom == 1.0f) {
+ // In XLarge view, we zoom down the workspace below all apps so it's still visible
+ if (zoom == 1.0f && !LauncherApplication.isScreenXLarge()) {
mWorkspace.setVisibility(View.GONE);
}
}
+
+ private void showToolbarButton(View button) {
+ button.setAlpha(1.0f);
+ 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);
+ button.setFocusable(false);
+ button.setClickable(false);
+ }
+
+ /**
+ * Helper function for showing or hiding a toolbar button, possibly animated.
+ *
+ * @param show If true, create an animation to the show the item. Otherwise, hide it.
+ * @param view The toolbar button to be animated
+ * @param seq A AnimatorSet that will be used to animate the transition. If null, the
+ * transition will not be animated.
+ */
+ private void hideOrShowToolbarButton(boolean show, final View view, AnimatorSet seq) {
+ final boolean showing = show;
+ final boolean hiding = !show;
+
+ final int duration = show ?
+ getResources().getInteger(R.integer.config_toolbarButtonFadeInTime) :
+ getResources().getInteger(R.integer.config_toolbarButtonFadeOutTime);
+
+ if (seq != null) {
+ Animator anim = ObjectAnimator.ofFloat(view, "alpha", show ? 1.0f : 0.0f);
+ anim.setDuration(duration);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (showing) showToolbarButton(view);
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (hiding) hideToolbarButton(view);
+ }
+ });
+ seq.play(anim);
+ } else {
+ if (showing) {
+ showToolbarButton(view);
+ } else {
+ hideToolbarButton(view);
+ }
+ }
+ }
+
+ /**
+ * Show/hide the appropriate toolbar buttons for newState.
+ * If showSeq or hideSeq is null, the transition will be done immediately (not animated).
+ *
+ * @param newState The state that is being switched to
+ * @param showSeq AnimatorSet in which to put "show" animations, or null.
+ * @param hideSeq AnimatorSet in which to put "hide" animations, or null.
+ */
+ private void hideAndShowToolbarButtons(State newState, AnimatorSet showSeq, AnimatorSet hideSeq) {
+ final View searchButton = findViewById(R.id.search_button_cluster);
+ final View allAppsButton = findViewById(R.id.all_apps_button);
+ final View divider = findViewById(R.id.divider);
+ final View configureButton = findViewById(R.id.configure_button);
+
+ switch (newState) {
+ case WORKSPACE:
+ hideOrShowToolbarButton(true, searchButton, showSeq);
+ hideOrShowToolbarButton(true, allAppsButton, showSeq);
+ hideOrShowToolbarButton(true, divider, showSeq);
+ hideOrShowToolbarButton(true, configureButton, showSeq);
+ mDeleteZone.setOverlappingViews(new View[] { allAppsButton, divider, configureButton });
+ mDeleteZone.setDragAndDropEnabled(true);
+ mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_workspace));
+ break;
+ case ALL_APPS:
+ hideOrShowToolbarButton(false, configureButton, hideSeq);
+ hideOrShowToolbarButton(false, searchButton, hideSeq);
+ hideOrShowToolbarButton(false, divider, hideSeq);
+ hideOrShowToolbarButton(false, allAppsButton, hideSeq);
+ mDeleteZone.setDragAndDropEnabled(false);
+ mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_all_apps));
+ break;
+ case CUSTOMIZE:
+ hideOrShowToolbarButton(false, allAppsButton, hideSeq);
+ hideOrShowToolbarButton(false, searchButton, hideSeq);
+ hideOrShowToolbarButton(false, divider, hideSeq);
+ hideOrShowToolbarButton(false, configureButton, hideSeq);
+ mDeleteZone.setDragAndDropEnabled(false);
+ break;
+ }
+ }
+
+ /**
+ * Helper method for the cameraZoomIn/cameraZoomOut animations
+ * @param view The view being animated
+ * @param state The state that we are moving in or out of -- either ALL_APPS or CUSTOMIZE
+ * @param scaleFactor The scale factor used for the zoom
+ */
+ private void setPivotsForZoom(View view, State state, float scaleFactor) {
+ final int height = view.getHeight();
+
+ view.setPivotX(view.getWidth() / 2.0f);
+ // 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) {
+ final float initialHeightFactor = 0.165f;
+ view.setPivotY((1 - initialHeightFactor) * height);
+ } else {
+ final float initialHeightFactor = 0.2f;
+ view.setPivotY(-initialHeightFactor * height);
+ }
+ }
+
+ /**
+ * Zoom the camera out from the workspace to reveal 'toView'.
+ * Assumes that the view to show is anchored at either the very top or very bottom
+ * of the screen.
+ * @param toState The state to zoom out to. Must be ALL_APPS or CUSTOMIZE.
+ */
+ private void cameraZoomOut(State toState, boolean animated) {
+ final Resources res = getResources();
+ final boolean toAllApps = (toState == State.ALL_APPS);
+
+ final int duration = toAllApps ?
+ res.getInteger(R.integer.config_allAppsZoomInTime) :
+ res.getInteger(R.integer.config_customizeZoomInTime);
+
+ final float scale = toAllApps ?
+ (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) :
+ (float) res.getInteger(R.integer.config_customizeZoomScaleFactor);
+
+ final View toView = toAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+
+ setPivotsForZoom(toView, toState, scale);
+
+ if (toAllApps) {
+ mWorkspace.shrink(ShrinkState.BOTTOM_HIDDEN, animated);
+ } else {
+ mWorkspace.shrink(ShrinkState.TOP, animated);
+ }
+
+ if (animated) {
+ ValueAnimator scaleAnim = ObjectAnimator.ofPropertyValuesHolder(toView,
+ PropertyValuesHolder.ofFloat("scaleX", scale, 1.0f),
+ PropertyValuesHolder.ofFloat("scaleY", scale, 1.0f));
+
+ scaleAnim.setDuration(duration);
+
+ if (toAllApps) {
+ toView.setAlpha(0f);
+ ObjectAnimator alphaAnim = ObjectAnimator.ofPropertyValuesHolder(toView,
+ PropertyValuesHolder.ofFloat("alpha", 1.0f));
+ alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
+ alphaAnim.setDuration(duration);
+ alphaAnim.start();
+ }
+
+ scaleAnim.setInterpolator(new Workspace.ZoomOutInterpolator());
+ scaleAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Prepare the position
+ toView.setTranslationX(0.0f);
+ toView.setTranslationY(0.0f);
+ toView.setVisibility(View.VISIBLE);
+ if (!toAllApps) {
+ toView.setAlpha(1.0f);
+ }
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // If we don't set the final scale values here, if this animation is cancelled
+ // it will have the wrong scale value and subsequent cameraPan animations will
+ // not fix that
+ toView.setScaleX(1.0f);
+ toView.setScaleY(1.0f);
+ }
+ });
+
+ AnimatorSet toolbarHideAnim = new AnimatorSet();
+ AnimatorSet toolbarShowAnim = new AnimatorSet();
+ hideAndShowToolbarButtons(toState, toolbarShowAnim, toolbarHideAnim);
+
+ // toView should appear right at the end of the workspace shrink animation
+ final int startDelay = 0;
+
+ if (mStateAnimation != null) mStateAnimation.cancel();
+ mStateAnimation = new AnimatorSet();
+ mStateAnimation.playTogether(scaleAnim, toolbarHideAnim);
+ mStateAnimation.play(scaleAnim).after(startDelay);
+
+ // Show the new toolbar buttons just as the main animation is ending
+ final int fadeInTime = res.getInteger(R.integer.config_toolbarButtonFadeInTime);
+ mStateAnimation.play(toolbarShowAnim).after(duration + startDelay - fadeInTime);
+ mStateAnimation.start();
+ } else {
+ toView.setTranslationX(0.0f);
+ toView.setTranslationY(0.0f);
+ toView.setScaleX(1.0f);
+ toView.setScaleY(1.0f);
+ toView.setVisibility(View.VISIBLE);
+ hideAndShowToolbarButtons(toState, null, null);
+ }
+ }
+
+ /**
+ * Zoom the camera back into the workspace, hiding 'fromView'.
+ * This is the opposite of cameraZoomOut.
+ * @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);
+
+ int duration = fromAllApps ?
+ res.getInteger(R.integer.config_allAppsZoomOutTime) :
+ res.getInteger(R.integer.config_customizeZoomOutTime);
+
+ float scaleFactor = fromAllApps ?
+ (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) :
+ (float) res.getInteger(R.integer.config_customizeZoomScaleFactor);
+
+ final View fromView = fromAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+
+ mCustomizePagedView.endChoiceMode();
+ mAllAppsPagedView.endChoiceMode();
+
+ setPivotsForZoom(fromView, fromState, scaleFactor);
+
+ if (!springLoaded) {
+ mWorkspace.unshrink(animated);
+ }
+
+ if (animated) {
+ if (mStateAnimation != null) mStateAnimation.cancel();
+ mStateAnimation = new AnimatorSet();
+ ValueAnimator scaleAnim = ObjectAnimator.ofPropertyValuesHolder(fromView,
+ PropertyValuesHolder.ofFloat("scaleX", scaleFactor),
+ PropertyValuesHolder.ofFloat("scaleY", scaleFactor));
+ scaleAnim.setDuration(duration);
+ scaleAnim.setInterpolator(new Workspace.ZoomInInterpolator());
+
+ ValueAnimator alphaAnim = ObjectAnimator.ofPropertyValuesHolder(fromView,
+ PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f));
+ alphaAnim.setDuration(res.getInteger(R.integer.config_allAppsFadeOutTime));
+ alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ fromView.setVisibility(View.GONE);
+ }
+ });
+
+ AnimatorSet toolbarHideAnim = new AnimatorSet();
+ AnimatorSet toolbarShowAnim = new AnimatorSet();
+ if (!springLoaded) {
+ hideAndShowToolbarButtons(State.WORKSPACE, toolbarShowAnim, toolbarHideAnim);
+ }
+
+ mStateAnimation.playTogether(scaleAnim, toolbarHideAnim, alphaAnim);
+
+ // Show the new toolbar buttons at the very end of the whole animation
+ final int fadeInTime = res.getInteger(R.integer.config_toolbarButtonFadeInTime);
+ final int unshrinkTime = res.getInteger(R.integer.config_workspaceUnshrinkTime);
+ mStateAnimation.play(toolbarShowAnim).after(unshrinkTime - fadeInTime);
+ mStateAnimation.start();
+ } else {
+ fromView.setVisibility(View.GONE);
+ if (!springLoaded) {
+ hideAndShowToolbarButtons(State.WORKSPACE, null, null);
+ }
+ }
+ }
+
+ /**
+ * Pan the camera in the vertical plane between 'fromView' and 'toView'.
+ * This is the transition used on xlarge screens to go between all apps and
+ * the home customization drawer.
+ * @param fromState The view to pan away from. Must be ALL_APPS or CUSTOMIZE.
+ * @param toState The view to pan into the frame. Must be ALL_APPS or CUSTOMIZE.
+ * @param animated If true, the transition will be animated.
+ */
+ private void cameraPan(State fromState, State toState, boolean animated) {
+ final Resources res = getResources();
+ final int duration = res.getInteger(R.integer.config_allAppsCameraPanTime);
+ final int workspaceHeight = mWorkspace.getHeight();
+
+ final boolean fromAllApps = (fromState == State.ALL_APPS);
+ final View fromView = fromAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+ final View toView = fromAllApps ? mHomeCustomizationDrawer : (View) mAllAppsGrid;
+
+ final float fromViewStartY = fromAllApps ? 0.0f : fromView.getY();
+ final float fromViewEndY = fromAllApps ? -fromView.getHeight() * 2 : workspaceHeight * 2;
+ final float toViewStartY = fromAllApps ? workspaceHeight * 2 : -toView.getHeight() * 2;
+ final float toViewEndY = fromAllApps ? workspaceHeight - toView.getHeight() : 0.0f;
+
+ mCustomizePagedView.endChoiceMode();
+ mAllAppsPagedView.endChoiceMode();
+
+ if (toState == State.ALL_APPS) {
+ mWorkspace.shrink(Workspace.ShrinkState.BOTTOM_HIDDEN, animated);
+ } else {
+ mWorkspace.shrink(Workspace.ShrinkState.TOP, animated);
+ }
+
+ if (animated) {
+ if (mStateAnimation != null) mStateAnimation.cancel();
+ mStateAnimation = new AnimatorSet();
+ mStateAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ toView.setVisibility(View.VISIBLE);
+ toView.setY(toViewStartY);
+ toView.setAlpha(1.0f);
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ fromView.setVisibility(View.GONE);
+ }
+ });
+
+ AnimatorSet toolbarHideAnim = new AnimatorSet();
+ AnimatorSet toolbarShowAnim = new AnimatorSet();
+ hideAndShowToolbarButtons(toState, toolbarShowAnim, toolbarHideAnim);
+
+ ObjectAnimator fromAnim = ObjectAnimator.ofFloat(fromView, "y",
+ fromViewStartY, fromViewEndY);
+ fromAnim.setDuration(duration);
+ ObjectAnimator toAnim = ObjectAnimator.ofPropertyValuesHolder(toView,
+ PropertyValuesHolder.ofFloat("y", toViewStartY, toViewEndY),
+ PropertyValuesHolder.ofFloat("scaleX", toView.getScaleX(), 1.0f),
+ PropertyValuesHolder.ofFloat("scaleY", toView.getScaleY(), 1.0f)
+ );
+ fromAnim.setDuration(duration);
+ mStateAnimation.playTogether(toolbarHideAnim, fromAnim, toAnim);
+
+ // Show the new toolbar buttons just as the main animation is ending
+ final int fadeInTime = res.getInteger(R.integer.config_toolbarButtonFadeInTime);
+ mStateAnimation.play(toolbarShowAnim).after(duration - fadeInTime);
+ mStateAnimation.start();
+ } else {
+ fromView.setY(fromViewEndY);
+ fromView.setVisibility(View.GONE);
+ toView.setY(toViewEndY);
+ toView.setScaleX(1.0f);
+ toView.setScaleY(1.0f);
+ toView.setVisibility(View.VISIBLE);
+ hideAndShowToolbarButtons(toState, null, null);
+ }
+ }
void showAllApps(boolean animated) {
- mAllAppsGrid.zoom(1.0f, animated);
+ if (mState == State.ALL_APPS) {
+ return;
+ }
+
+ if (LauncherApplication.isScreenXLarge()) {
+ if (mState == State.CUSTOMIZE) {
+ cameraPan(State.CUSTOMIZE, State.ALL_APPS, animated);
+ } else {
+ 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;
+
+ // send an accessibility event to announce the context change
+ getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ }
+
+ void showWorkspace(boolean animated) {
+ showWorkspace(animated, null);
+ }
+
+ void showWorkspace(boolean animated, CellLayout layout) {
+ if (layout != null) {
+ // always animated, but that's ok since we never specify a layout and
+ // want no animation
+ mWorkspace.unshrink(layout);
+ } else {
+ mWorkspace.unshrink(animated);
+ }
+ if (mState == State.ALL_APPS) {
+ closeAllApps(animated);
+ } else if (mState == State.CUSTOMIZE) {
+ hideCustomizationDrawer(animated);
+ }
+
+ // Change the state *after* we've called all the transition code
+ mState = State.WORKSPACE;
+
+ // send an accessibility event to announce the context change
+ getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ }
+
+ void enterSpringLoadedDragMode(CellLayout layout) {
+ mWorkspace.enterSpringLoadedDragMode(layout);
+ if (mState == State.ALL_APPS) {
+ cameraZoomIn(State.ALL_APPS, true, true);
+ mState = State.ALL_APPS_SPRING_LOADED;
+ } else if (mState == State.CUSTOMIZE) {
+ cameraZoomIn(State.CUSTOMIZE, true, true);
+ mState = State.CUSTOMIZE_SPRING_LOADED;
+ }/* else {
+ // we're already in spring loaded mode; don't do anything
+ }*/
+ }
+
+ void exitSpringLoadedDragMode() {
+ if (mState == State.ALL_APPS_SPRING_LOADED) {
+ mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.BOTTOM_VISIBLE);
+ cameraZoomOut(State.ALL_APPS, true);
+ mState = State.ALL_APPS;
+ } else if (mState == State.CUSTOMIZE_SPRING_LOADED) {
+ mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.TOP);
+ cameraZoomOut(State.CUSTOMIZE, true);
+ mState = State.CUSTOMIZE;
+ }/* else {
+ // we're not in spring loaded mode; don't do anything
+ }*/
}
/**
@@ -1973,11 +3025,15 @@
* - From another workspace
*/
void closeAllApps(boolean animated) {
- if (mAllAppsGrid.isVisible()) {
+ if (mState == State.ALL_APPS || mState == State.ALL_APPS_SPRING_LOADED) {
mWorkspace.setVisibility(View.VISIBLE);
- mAllAppsGrid.zoom(0.0f, animated);
+ if (LauncherApplication.isScreenXLarge()) {
+ cameraZoomIn(State.ALL_APPS, animated);
+ } else {
+ mAllAppsGrid.zoom(0.0f, animated);
+ }
((View)mAllAppsGrid).setFocusable(false);
- mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus();
+ mWorkspace.getChildAt(mWorkspace.getCurrentPage()).requestFocus();
}
}
@@ -1989,6 +3045,125 @@
// TODO
}
+ // Show the customization drawer (only exists in x-large configuration)
+ private void showCustomizationDrawer(boolean animated) {
+ if (mState == State.ALL_APPS) {
+ cameraPan(State.ALL_APPS, State.CUSTOMIZE, animated);
+ } else {
+ cameraZoomOut(State.CUSTOMIZE, animated);
+ }
+ // Change the state *after* we've called all the transition code
+ mState = State.CUSTOMIZE;
+ }
+
+ // 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);
+ }
+ }
+
+ void addExternalItemToScreen(ItemInfo itemInfo, CellLayout layout) {
+ if (!mWorkspace.addExternalItemToScreen(itemInfo, layout)) {
+ showOutOfSpaceMessage();
+ }
+ }
+
+ void onWorkspaceClick(CellLayout layout) {
+ showWorkspace(true, layout);
+ }
+
+ // if successful in getting icon, return it; otherwise, set button to use default drawable
+ private Drawable.ConstantState updateButtonWithIconFromExternalActivity(
+ int buttonId, ComponentName activityName, int fallbackDrawableId) {
+ ImageView button = (ImageView) findViewById(buttonId);
+ Drawable toolbarIcon = null;
+ try {
+ PackageManager packageManager = getPackageManager();
+ // Look for the toolbar icon specified in the activity meta-data
+ Bundle metaData = packageManager.getActivityInfo(
+ activityName, PackageManager.GET_META_DATA).metaData;
+ if (metaData != null) {
+ int iconResId = metaData.getInt(TOOLBAR_ICON_METADATA_NAME);
+ if (iconResId != 0) {
+ Resources res = packageManager.getResourcesForActivity(activityName);
+ toolbarIcon = res.getDrawable(iconResId);
+ }
+ }
+ } catch (NameNotFoundException e) {
+ // Do nothing
+ }
+ // If we were unable to find the icon via the meta-data, use a generic one
+ if (toolbarIcon == null) {
+ button.setImageResource(fallbackDrawableId);
+ return null;
+ } else {
+ button.setImageDrawable(toolbarIcon);
+ return toolbarIcon.getConstantState();
+ }
+ }
+
+ private void updateButtonWithDrawable(int buttonId, Drawable.ConstantState d) {
+ ImageView button = (ImageView) findViewById(buttonId);
+ button.setImageDrawable(d.newDrawable(getResources()));
+ }
+
+ private void updateGlobalSearchIcon() {
+ if (LauncherApplication.isScreenXLarge()) {
+ final SearchManager searchManager =
+ (SearchManager) getSystemService(Context.SEARCH_SERVICE);
+ ComponentName activityName = searchManager.getGlobalSearchActivity();
+ if (activityName != null) {
+ sGlobalSearchIcon = updateButtonWithIconFromExternalActivity(
+ R.id.search_button, activityName, R.drawable.search_button_generic);
+ } else {
+ findViewById(R.id.search_button).setVisibility(View.GONE);
+ }
+ }
+ }
+
+ private void updateGlobalSearchIcon(Drawable.ConstantState d) {
+ updateButtonWithDrawable(R.id.search_button, d);
+ }
+
+ private void updateVoiceSearchIcon() {
+ if (LauncherApplication.isScreenXLarge()) {
+ 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);
+ } else {
+ findViewById(R.id.voice_button).setVisibility(View.GONE);
+ }
+ }
+ }
+
+ private void updateVoiceSearchIcon(Drawable.ConstantState d) {
+ updateButtonWithDrawable(R.id.voice_button, d);
+ }
+
+ /**
+ * 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 = updateButtonWithIconFromExternalActivity(
+ R.id.market_button, activityName, R.drawable.app_market_generic);
+ }
+ }
+ }
+
+ private void updateAppMarketIcon(Drawable.ConstantState d) {
+ updateButtonWithDrawable(R.id.market_button, d);
+ }
+
/**
* Displays the shortcut creation dialog and launches, if necessary, the
* appropriate activity.
@@ -2041,7 +3216,6 @@
switch (which) {
case AddAdapter.ITEM_SHORTCUT: {
- // Insert extra item to handle picking application
pickShortcut();
break;
}
@@ -2089,7 +3263,7 @@
}
public void onShow(DialogInterface dialog) {
- mWaitingForResult = true;
+ mWaitingForResult = true;
}
}
@@ -2106,7 +3280,7 @@
if (mPaused || "lock".equals(reason)) {
animate = false;
}
- closeAllApps(animate);
+ showWorkspace(animate);
}
}
}
@@ -2154,12 +3328,16 @@
*/
public int getCurrentWorkspaceScreen() {
if (mWorkspace != null) {
- return mWorkspace.getCurrentScreen();
+ return mWorkspace.getCurrentPage();
} else {
return SCREEN_COUNT / 2;
}
}
+ void setAllAppsPagedView(AllAppsPagedView view) {
+ mAllAppsPagedView = view;
+ }
+
/**
* Refreshes the shortcuts shown on the workspace.
*
@@ -2209,15 +3387,15 @@
break;
case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
- (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()),
- (UserFolderInfo) item);
+ (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
+ (UserFolderInfo) 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.getCurrentScreen()),
+ (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
(LiveFolderInfo) item);
workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1,
false);
@@ -2265,6 +3443,8 @@
workspace.addInScreen(item.hostView, item.screen, item.cellX,
item.cellY, item.spanX, item.spanY, false);
+ addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);
+
workspace.requestLayout();
mDesktopItems.add(item);
@@ -2285,7 +3465,7 @@
if (mSavedState != null) {
if (!mWorkspace.hasFocus()) {
- mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus();
+ mWorkspace.getChildAt(mWorkspace.getCurrentPage()).requestFocus();
}
final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS);
@@ -2314,12 +3494,26 @@
}
/**
+ * Updates the icons on the launcher that are affected by changes to the package list
+ * on the device.
+ */
+ private void updateIconsAffectedByPackageManagerChanges() {
+ updateAppMarketIcon();
+ updateGlobalSearchIcon();
+ updateVoiceSearchIcon();
+ }
+
+ /**
* Add the icons for all apps.
*
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindAllApplications(ArrayList<ApplicationInfo> apps) {
mAllAppsGrid.setApps(apps);
+ if (mCustomizePagedView != null) {
+ mCustomizePagedView.setApps(apps);
+ }
+ updateIconsAffectedByPackageManagerChanges();
}
/**
@@ -2331,6 +3525,10 @@
setLoadOnResume();
removeDialog(DIALOG_CREATE_SHORTCUT);
mAllAppsGrid.addApps(apps);
+ if (mCustomizePagedView != null) {
+ mCustomizePagedView.addApps(apps);
+ }
+ updateIconsAffectedByPackageManagerChanges();
}
/**
@@ -2343,6 +3541,10 @@
removeDialog(DIALOG_CREATE_SHORTCUT);
mWorkspace.updateShortcuts(apps);
mAllAppsGrid.updateApps(apps);
+ if (mCustomizePagedView != null) {
+ mCustomizePagedView.updateApps(apps);
+ }
+ updateIconsAffectedByPackageManagerChanges();
}
/**
@@ -2356,6 +3558,63 @@
mWorkspace.removeItems(apps);
}
mAllAppsGrid.removeApps(apps);
+ if (mCustomizePagedView != null) {
+ mCustomizePagedView.removeApps(apps);
+ }
+ updateIconsAffectedByPackageManagerChanges();
+ }
+
+ /**
+ * A number of packages were updated.
+ */
+ public void bindPackagesUpdated() {
+ // update the customization drawer contents
+ if (mCustomizePagedView != null) {
+ mCustomizePagedView.update();
+ }
+ }
+
+ private int mapConfigurationOriActivityInfoOri(int configOri) {
+ final Display d = getWindowManager().getDefaultDisplay();
+ int naturalOri = Configuration.ORIENTATION_LANDSCAPE;
+ switch (d.getRotation()) {
+ case Surface.ROTATION_0:
+ case Surface.ROTATION_180:
+ // We are currently in the same basic orientation as the natural orientation
+ naturalOri = configOri;
+ break;
+ case Surface.ROTATION_90:
+ case Surface.ROTATION_270:
+ // We are currently in the other basic orientation to the natural orientation
+ naturalOri = (configOri == Configuration.ORIENTATION_LANDSCAPE) ?
+ Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
+ break;
+ }
+
+ int[] oriMap = {
+ ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
+ ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
+ ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
+ };
+ // Since the map starts at portrait, we need to offset if this device's natural orientation
+ // is landscape.
+ int indexOffset = 0;
+ if (naturalOri == Configuration.ORIENTATION_LANDSCAPE) {
+ indexOffset = 1;
+ }
+ return oriMap[(d.getRotation() + indexOffset) % 4];
+ }
+ public void lockScreenOrientation() {
+ setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
+ .getConfiguration().orientation));
+ }
+ public void unlockScreenOrientation() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ }
+ }, mRestoreScreenOrientationDelay);
}
/**
diff --git a/src/com/android/launcher2/LauncherAppWidgetHost.java b/src/com/android/launcher2/LauncherAppWidgetHost.java
index a5761ec..68d4903 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHost.java
@@ -30,10 +30,16 @@
public LauncherAppWidgetHost(Context context, int hostId) {
super(context, hostId);
}
-
+
@Override
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
return new LauncherAppWidgetHostView(context);
}
+
+ @Override
+ public void stopListening() {
+ super.stopListening();
+ clearViews();
+ }
}
diff --git a/src/com/android/launcher2/LauncherAppWidgetHostView.java b/src/com/android/launcher2/LauncherAppWidgetHostView.java
index c45140e..85a80f9 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHostView.java
@@ -28,13 +28,13 @@
/**
* {@inheritDoc}
*/
-public class LauncherAppWidgetHostView extends AppWidgetHostView {
+public class LauncherAppWidgetHostView extends AppWidgetHostView
+ implements VisibilityChangedBroadcaster {
private boolean mHasPerformedLongPress;
-
private CheckForLongPress mPendingCheckForLongPress;
-
private LayoutInflater mInflater;
-
+ private VisibilityChangedListener mOnVisibilityChangedListener;
+
public LauncherAppWidgetHostView(Context context) {
super(context);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -110,4 +110,16 @@
removeCallbacks(mPendingCheckForLongPress);
}
}
+
+ public void setVisibilityChangedListener(VisibilityChangedListener listener) {
+ mOnVisibilityChangedListener = listener;
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ if (mOnVisibilityChangedListener != null) {
+ mOnVisibilityChangedListener.receiveVisibilityChangedMessage(this);
+ }
+ super.onVisibilityChanged(changedView, visibility);
+ }
}
diff --git a/src/com/android/launcher2/LauncherAppWidgetInfo.java b/src/com/android/launcher2/LauncherAppWidgetInfo.java
index 8499ebb..844abb5 100644
--- a/src/com/android/launcher2/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher2/LauncherAppWidgetInfo.java
@@ -17,30 +17,55 @@
package com.android.launcher2;
import android.appwidget.AppWidgetHostView;
+import android.content.ComponentName;
import android.content.ContentValues;
/**
- * Represents a widget, which just contains an identifier.
+ * Represents a widget (either instantiated or about to be) in the Launcher.
*/
class LauncherAppWidgetInfo extends ItemInfo {
/**
+ * Indicates that the widget hasn't been instantiated yet.
+ */
+ static final int NO_ID = -1;
+
+ /**
* Identifier for this widget when talking with
* {@link android.appwidget.AppWidgetManager} for updates.
*/
- int appWidgetId;
-
+ int appWidgetId = NO_ID;
+
+ ComponentName providerName;
+
+ // TODO: Are these necessary here?
+ int minWidth = -1;
+ int minHeight = -1;
+
/**
* View that holds this widget after it's been created. This view isn't created
* until Launcher knows it's needed.
*/
AppWidgetHostView hostView = null;
+ /**
+ * Constructor for use with AppWidgets that haven't been instantiated yet.
+ */
+ LauncherAppWidgetInfo(ComponentName providerName) {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+ this.providerName = providerName;
+
+ // Since the widget isn't instantiated yet, we don't know these values. Set them to -1
+ // to indicate that they should be calculated based on the layout and minWidth/minHeight
+ spanX = -1;
+ spanY = -1;
+ }
+
LauncherAppWidgetInfo(int appWidgetId) {
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
this.appWidgetId = appWidgetId;
}
-
+
@Override
void onAddToDatabase(ContentValues values) {
super.onAddToDatabase(values);
@@ -52,7 +77,6 @@
return "AppWidget(id=" + Integer.toString(appWidgetId) + ")";
}
-
@Override
void unbind() {
super.unbind();
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index eda92d9..ed007dd 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -20,6 +20,7 @@
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.database.ContentObserver;
import android.os.Handler;
import dalvik.system.VMRuntime;
@@ -27,6 +28,9 @@
public class LauncherApplication extends Application {
public LauncherModel mModel;
public IconCache mIconCache;
+ private static boolean sIsScreenXLarge;
+ private static float sScreenDensity;
+ private static final boolean ENABLE_ROTATION = false;
@Override
public void onCreate() {
@@ -34,6 +38,10 @@
super.onCreate();
+ // set sIsScreenXLarge and sScreenDensity *before* creating icon cache
+ sIsScreenXLarge = (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ sScreenDensity = getResources().getDisplayMetrics().density;
+
mIconCache = new IconCache(this);
mModel = new LauncherModel(this, mIconCache);
@@ -46,6 +54,7 @@
filter = new IntentFilter();
filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ filter.addAction(Intent.ACTION_LOCALE_CHANGED);
registerReceiver(mModel, filter);
// Register for changes to the favorites
@@ -89,4 +98,16 @@
LauncherModel getModel() {
return mModel;
}
+
+ public static boolean isInPlaceRotationEnabled() {
+ return sIsScreenXLarge && ENABLE_ROTATION;
+ }
+
+ public static boolean isScreenXLarge() {
+ return sIsScreenXLarge;
+ }
+
+ public static float getScreenDensity() {
+ return sScreenDensity;
+ }
}
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index b819510..0052737 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -16,6 +16,15 @@
package com.android.launcher2;
+import java.lang.ref.WeakReference;
+import java.net.URISyntaxException;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
@@ -23,9 +32,9 @@
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
+import android.content.Context;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
-import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
@@ -38,22 +47,13 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
-
-import java.lang.ref.WeakReference;
-import java.net.URISyntaxException;
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
+import android.util.Log;
import com.android.launcher.R;
+import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
@@ -95,6 +95,9 @@
private Bitmap mDefaultIcon;
+ private static int mCellCountX;
+ private static int mCellCountY;
+
public interface Callbacks {
public boolean setLoadOnResume();
public int getCurrentWorkspaceScreen();
@@ -107,6 +110,7 @@
public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);
public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);
+ public void bindPackagesUpdated();
public boolean isAllAppsVisible();
}
@@ -116,7 +120,7 @@
mIconCache = iconCache;
mDefaultIcon = Utilities.createIconBitmap(
- app.getPackageManager().getDefaultActivityIcon(), app);
+ mIconCache.getFullResDefaultActivityIcon(), app);
mAllAppsLoadDelay = app.getResources().getInteger(R.integer.config_allAppsBatchLoadDelay);
@@ -147,6 +151,7 @@
*/
static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen,
int cellX, int cellY) {
+
item.container = container;
item.screen = screen;
item.cellX = cellX;
@@ -157,8 +162,8 @@
final ContentResolver cr = context.getContentResolver();
values.put(LauncherSettings.Favorites.CONTAINER, item.container);
- values.put(LauncherSettings.Favorites.CELLX, item.cellX);
- values.put(LauncherSettings.Favorites.CELLY, item.cellY);
+ values.put(LauncherSettings.Favorites.CELLX, cellX);
+ values.put(LauncherSettings.Favorites.CELLY, cellY);
values.put(LauncherSettings.Favorites.SCREEN, item.screen);
sWorker.post(new Runnable() {
@@ -187,6 +192,48 @@
}
/**
+ * Returns an ItemInfo array containing all the items in the LauncherModel.
+ * The ItemInfo.id is not set through this function.
+ */
+ static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {
+ ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
+ final ContentResolver cr = context.getContentResolver();
+ Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {
+ LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,
+ LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
+ LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null);
+
+ final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+ final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+ final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+ final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+ final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+ final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
+ final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
+
+ try {
+ while (c.moveToNext()) {
+ ItemInfo item = new ItemInfo();
+ item.cellX = c.getInt(cellXIndex);
+ item.cellY = c.getInt(cellYIndex);
+ item.spanX = c.getInt(spanXIndex);
+ item.spanY = c.getInt(spanYIndex);
+ item.container = c.getInt(containerIndex);
+ item.itemType = c.getInt(itemTypeIndex);
+ item.screen = c.getInt(screenIndex);
+
+ items.add(item);
+ }
+ } catch (Exception e) {
+ items.clear();
+ } finally {
+ c.close();
+ }
+
+ return items;
+ }
+
+ /**
* Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
*/
FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {
@@ -245,9 +292,10 @@
final ContentValues values = new ContentValues();
final ContentResolver cr = context.getContentResolver();
-
item.onAddToDatabase(values);
+ item.updateValuesWithCoordinates(values, cellX, cellY);
+
Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
@@ -257,6 +305,32 @@
}
/**
+ * Creates a new unique child id, for a given cell span across all layouts.
+ */
+ static int getCellLayoutChildId(
+ int cellId, int screen, int localCellX, int localCellY, int spanX, int spanY) {
+ return ((cellId & 0xFF) << 24)
+ | (screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);
+ }
+
+ static int getCellCountX() {
+ return mCellCountX;
+ }
+
+ static int getCellCountY() {
+ return mCellCountY;
+ }
+
+ /**
+ * Updates the model orientation helper to take into account the current layout dimensions
+ * when performing local/canonical coordinate transformations.
+ */
+ static void updateWorkspaceLayoutCells(int shortAxisCellCount, int longAxisCellCount) {
+ mCellCountX = shortAxisCellCount;
+ mCellCountY = longAxisCellCount;
+ }
+
+ /**
* Update an item to the database in a specified container.
*/
static void updateItemInDatabase(Context context, ItemInfo item) {
@@ -264,6 +338,7 @@
final ContentResolver cr = context.getContentResolver();
item.onAddToDatabase(values);
+ item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null);
}
@@ -309,7 +384,7 @@
*/
public void onReceive(Context context, Intent intent) {
if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);
-
+
final String action = intent.getAction();
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
@@ -350,25 +425,41 @@
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));
// Then, rebind everything.
- boolean runLoader = true;
- if (mCallbacks != null) {
- Callbacks callbacks = mCallbacks.get();
- if (callbacks != null) {
- // If they're paused, we can skip loading, because they'll do it again anyway
- if (callbacks.setLoadOnResume()) {
- runLoader = false;
- }
- }
- }
- if (runLoader) {
- startLoader(mApp, false);
- }
-
+ startLoaderFromBackground();
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
enqueuePackageUpdated(new PackageUpdatedTask(
PackageUpdatedTask.OP_UNAVAILABLE, packages));
+ } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ // If we have changed locale we need to clear out the labels in all apps.
+ // Do this here because if the launcher activity is running it will be restarted.
+ // If it's not running startLoaderFromBackground will merely tell it that it needs
+ // to reload. Either way, mAllAppsLoaded will be cleared so it re-reads everything
+ // next time.
+ mAllAppsLoaded = false;
+ startLoaderFromBackground();
+ }
+ }
+ /**
+ * When the launcher is in the background, it's possible for it to miss paired
+ * configuration changes. So whenever we trigger the loader from the background
+ * tell the launcher that it needs to re-run the loader when it comes back instead
+ * of doing it now.
+ */
+ public void startLoaderFromBackground() {
+ boolean runLoader = false;
+ if (mCallbacks != null) {
+ Callbacks callbacks = mCallbacks.get();
+ if (callbacks != null) {
+ // Only actually run the loader if they're not paused.
+ if (!callbacks.setLoadOnResume()) {
+ runLoader = true;
+ }
+ }
+ }
+ if (runLoader) {
+ startLoader(mApp, false);
}
}
@@ -401,6 +492,9 @@
mLoaderTask.stopLocked();
}
}
+ mItems.clear();
+ mAppWidgets.clear();
+ mFolders.clear();
}
/**
@@ -474,7 +568,7 @@
}
if (DEBUG_LOADERS) {
Log.d(TAG, "waited "
- + (SystemClock.uptimeMillis()-workspaceWaitTime)
+ + (SystemClock.uptimeMillis()-workspaceWaitTime)
+ "ms for previous step to finish binding");
}
}
@@ -494,7 +588,6 @@
android.os.Process.setThreadPriority(mIsLaunching
? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
}
-
if (loadWorkspaceFirst) {
if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
loadAndBindWorkspace();
@@ -596,14 +689,13 @@
if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
return true;
}
-
for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
if (occupied[item.screen][x][y] != null) {
Log.e(TAG, "Error loading shortcut " + item
- + " into cell (" + item.screen + ":"
+ + " into cell (" + item.screen + ":"
+ x + "," + y
- + ") occupied by "
+ + ") occupied by "
+ occupied[item.screen][x][y]);
return false;
}
@@ -635,7 +727,8 @@
final Cursor c = contentResolver.query(
LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
- final ItemInfo occupied[][][] = new ItemInfo[Launcher.SCREEN_COUNT][Launcher.NUMBER_CELLS_X][Launcher.NUMBER_CELLS_Y];
+ final ItemInfo occupied[][][] =
+ new ItemInfo[Launcher.SCREEN_COUNT][mCellCountX][mCellCountY];
try {
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
@@ -744,7 +837,6 @@
UserFolderInfo folderInfo = findOrMakeUserFolder(mFolders, id);
folderInfo.title = c.getString(titleIndex);
-
folderInfo.id = id;
container = c.getInt(containerIndex);
folderInfo.container = container;
@@ -756,7 +848,6 @@
if (!checkItemPlacement(occupied, folderInfo)) {
break;
}
-
switch (container) {
case LauncherSettings.Favorites.CONTAINER_DESKTOP:
mItems.add(folderInfo);
@@ -779,7 +870,6 @@
itemsToRemove.add(id);
} else {
LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(mFolders, id);
-
intentDescription = c.getString(intentIndex);
intent = null;
if (intentDescription != null) {
@@ -825,7 +915,7 @@
final AppWidgetProviderInfo provider =
widgets.getAppWidgetInfo(appWidgetId);
-
+
if (!isSafeMode && (provider == null || provider.provider == null ||
provider.provider.getPackageName() == null)) {
Log.e(TAG, "Deleting widget that isn't installed anymore: id="
@@ -886,13 +976,13 @@
if (DEBUG_LOADERS) {
Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");
Log.d(TAG, "workspace layout: ");
- for (int y = 0; y < Launcher.NUMBER_CELLS_Y; y++) {
+ for (int y = 0; y < mCellCountY; y++) {
String line = "";
for (int s = 0; s < Launcher.SCREEN_COUNT; s++) {
if (s > 0) {
line += " | ";
}
- for (int x = 0; x < Launcher.NUMBER_CELLS_X; x++) {
+ for (int x = 0; x < mCellCountX; x++) {
line += ((occupied[s][x][y] != null) ? "#" : ".");
}
}
@@ -1116,7 +1206,7 @@
startIndex = i;
for (int j=0; i<N && j<batchSize; j++) {
// This builds the icon bitmaps.
- mAllAppsList.add(new ApplicationInfo(apps.get(i), mIconCache));
+ mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i), mIconCache));
i++;
}
@@ -1279,6 +1369,15 @@
}
});
}
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (callbacks == mCallbacks.get()) {
+ callbacks.bindPackagesUpdated();
+ }
+ }
+ });
}
}
@@ -1374,7 +1473,8 @@
Resources resources = packageManager.getResourcesForApplication(packageName);
if (resources != null) {
final int id = resources.getIdentifier(resourceName, null, null);
- icon = Utilities.createIconBitmap(resources.getDrawable(id), context);
+ icon = Utilities.createIconBitmap(
+ mIconCache.getFullResIcon(resources, id), context);
}
} catch (Exception e) {
// drop this. we have other places to look for icons
@@ -1423,16 +1523,69 @@
}
ShortcutInfo addShortcut(Context context, Intent data,
- CellLayout.CellInfo cellInfo, boolean notify) {
+ int screen, int cellX, int cellY, boolean notify) {
- final ShortcutInfo info = infoFromShortcutIntent(context, data);
+ final ShortcutInfo info = infoFromShortcutIntent(context, data, null);
addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
- cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
+ screen, cellX, cellY, notify);
return info;
}
- private ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {
+ /**
+ * Attempts to find an AppWidgetProviderInfo that matches the given component.
+ */
+ AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,
+ ComponentName component) {
+ List<AppWidgetProviderInfo> widgets =
+ AppWidgetManager.getInstance(context).getInstalledProviders();
+ for (AppWidgetProviderInfo info : widgets) {
+ if (info.provider.equals(component)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a list of all the widgets that can handle configuration with a particular mimeType.
+ */
+ List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {
+ final PackageManager packageManager = context.getPackageManager();
+ final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =
+ new ArrayList<WidgetMimeTypeHandlerData>();
+
+ final Intent supportsIntent =
+ new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);
+ supportsIntent.setType(mimeType);
+
+ // Create a set of widget configuration components that we can test against
+ final List<AppWidgetProviderInfo> widgets =
+ AppWidgetManager.getInstance(context).getInstalledProviders();
+ final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =
+ new HashMap<ComponentName, AppWidgetProviderInfo>();
+ for (AppWidgetProviderInfo info : widgets) {
+ configurationComponentToWidget.put(info.configure, info);
+ }
+
+ // Run through each of the intents that can handle this type of clip data, and cross
+ // reference them with the components that are actual configuration components
+ final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo info : activities) {
+ final ActivityInfo activityInfo = info.activityInfo;
+ final ComponentName infoComponent = new ComponentName(activityInfo.packageName,
+ activityInfo.name);
+ if (configurationComponentToWidget.containsKey(infoComponent)) {
+ supportedConfigurationActivities.add(
+ new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,
+ configurationComponentToWidget.get(infoComponent)));
+ }
+ }
+ return supportedConfigurationActivities;
+ }
+
+ ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
@@ -1455,7 +1608,8 @@
Resources resources = packageManager.getResourcesForApplication(
iconResource.packageName);
final int id = resources.getIdentifier(iconResource.resourceName, null, null);
- icon = Utilities.createIconBitmap(resources.getDrawable(id), context);
+ icon = Utilities.createIconBitmap(
+ mIconCache.getFullResIcon(resources, id), context);
} catch (Exception e) {
Log.w(TAG, "Could not load shortcut icon: " + extra);
}
@@ -1465,8 +1619,12 @@
final ShortcutInfo info = new ShortcutInfo();
if (icon == null) {
- icon = getFallbackIcon();
- info.usingFallbackIcon = true;
+ if (fallbackIcon != null) {
+ icon = fallbackIcon;
+ } else {
+ icon = getFallbackIcon();
+ info.usingFallbackIcon = true;
+ }
}
info.setIcon(icon);
@@ -1478,7 +1636,7 @@
return info;
}
- private static void loadLiveFolderIcon(Context context, Cursor c, int iconTypeIndex,
+ private void loadLiveFolderIcon(Context context, Cursor c, int iconTypeIndex,
int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
int iconType = c.getInt(iconTypeIndex);
@@ -1488,13 +1646,14 @@
String resourceName = c.getString(iconResourceIndex);
PackageManager packageManager = context.getPackageManager();
try {
- Resources resources = packageManager.getResourcesForApplication(packageName);
- final int id = resources.getIdentifier(resourceName, null, null);
- liveFolderInfo.icon = Utilities.createIconBitmap(resources.getDrawable(id),
- context);
- } catch (Exception e) {
+ Resources appResources = packageManager.getResourcesForApplication(packageName);
+ final int id = appResources.getIdentifier(resourceName, null, null);
liveFolderInfo.icon = Utilities.createIconBitmap(
- context.getResources().getDrawable(R.drawable.ic_launcher_folder),
+ 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();
@@ -1502,8 +1661,9 @@
liveFolderInfo.iconResource.resourceName = resourceName;
break;
default:
+ Resources resources = context.getResources();
liveFolderInfo.icon = Utilities.createIconBitmap(
- context.getResources().getDrawable(R.drawable.ic_launcher_folder),
+ mIconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder),
context);
}
}
@@ -1587,6 +1747,14 @@
return sCollator.compare(a.title.toString(), b.title.toString());
}
};
+ public static final Comparator<ApplicationInfo> APP_INSTALL_TIME_COMPARATOR
+ = new Comparator<ApplicationInfo>() {
+ public final int compare(ApplicationInfo a, ApplicationInfo b) {
+ if (a.firstInstallTime < b.firstInstallTime) return 1;
+ if (a.firstInstallTime > b.firstInstallTime) return -1;
+ return 0;
+ }
+ };
public void dumpState() {
Log.d(TAG, "mCallbacks=" + mCallbacks);
diff --git a/src/com/android/launcher2/LiveFolderInfo.java b/src/com/android/launcher2/LiveFolderInfo.java
index 7d0a0f5..74b0217 100644
--- a/src/com/android/launcher2/LiveFolderInfo.java
+++ b/src/com/android/launcher2/LiveFolderInfo.java
@@ -18,7 +18,6 @@
import android.content.ContentValues;
import android.content.Intent;
-import android.graphics.drawable.Drawable;
import android.graphics.Bitmap;
import android.net.Uri;
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
new file mode 100644
index 0000000..4a0f44e
--- /dev/null
+++ b/src/com/android/launcher2/PagedView.java
@@ -0,0 +1,1440 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.view.ActionMode;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.Checkable;
+import android.widget.Scroller;
+
+import com.android.launcher.R;
+
+/**
+ * An abstraction of the original Workspace which supports browsing through a
+ * sequential list of "pages"
+ */
+public abstract class PagedView extends ViewGroup {
+ private static final String TAG = "PagedView";
+ protected static final int INVALID_PAGE = -1;
+
+ // the min drag distance for a fling to register, to prevent random page shifts
+ private static final int MIN_LENGTH_FOR_FLING = 25;
+ // The min drag distance to trigger a page shift (regardless of velocity)
+ private static final int MIN_LENGTH_FOR_MOVE = 200;
+
+ private static final int PAGE_SNAP_ANIMATION_DURATION = 550;
+ protected static final float NANOTIME_DIV = 1000000000.0f;
+
+ private static final float OVERSCROLL_DAMP_FACTOR = 0.08f;
+ private static final int MINIMUM_SNAP_VELOCITY = 2200;
+ private static final int MIN_FLING_VELOCITY = 250;
+
+ // the velocity at which a fling gesture will cause us to snap to the next page
+ protected int mSnapVelocity = 500;
+
+ protected float mSmoothingTime;
+ protected float mTouchX;
+
+ protected boolean mFirstLayout = true;
+
+ protected int mCurrentPage;
+ protected int mNextPage = INVALID_PAGE;
+ protected int mRestorePage = -1;
+ protected int mMaxScrollX;
+ protected Scroller mScroller;
+ private VelocityTracker mVelocityTracker;
+
+ private float mDownMotionX;
+ protected float mLastMotionX;
+ protected float mLastMotionY;
+ private int mLastScreenCenter = -1;
+
+ protected final static int TOUCH_STATE_REST = 0;
+ protected final static int TOUCH_STATE_SCROLLING = 1;
+ protected final static int TOUCH_STATE_PREV_PAGE = 2;
+ protected final static int TOUCH_STATE_NEXT_PAGE = 3;
+ protected final static float ALPHA_QUANTIZE_LEVEL = 0.0001f;
+
+ protected int mTouchState = TOUCH_STATE_REST;
+
+ protected OnLongClickListener mLongClickListener;
+
+ protected boolean mAllowLongPress = true;
+
+ protected int mTouchSlop;
+ private int mPagingTouchSlop;
+ private int mMaximumVelocity;
+ protected int mPageSpacing;
+ protected int mPageLayoutPaddingTop;
+ protected int mPageLayoutPaddingBottom;
+ protected int mPageLayoutPaddingLeft;
+ protected int mPageLayoutPaddingRight;
+ protected int mPageLayoutWidthGap;
+ protected int mPageLayoutHeightGap;
+ protected int mCellCountX;
+ protected int mCellCountY;
+ protected boolean mCenterPagesVertically;
+ protected boolean mAllowOverScroll = true;
+ protected int mUnboundedScrollX;
+
+ // parameter that adjusts the layout to be optimized for CellLayouts with that scale factor
+ protected float mLayoutScale = 1.0f;
+
+ protected static final int INVALID_POINTER = -1;
+
+ protected int mActivePointerId = INVALID_POINTER;
+
+ private PageSwitchListener mPageSwitchListener;
+
+ private ArrayList<Boolean> mDirtyPageContent;
+ private boolean mDirtyPageAlpha;
+
+ // choice modes
+ protected static final int CHOICE_MODE_NONE = 0;
+ protected static final int CHOICE_MODE_SINGLE = 1;
+ // Multiple selection mode is not supported by all Launcher actions atm
+ protected static final int CHOICE_MODE_MULTIPLE = 2;
+
+ protected int mChoiceMode;
+ private ActionMode mActionMode;
+
+ // NOTE: This is a shared icon cache across all the PagedViews. Currently it is only used in
+ // AllApps and Customize, and allows them to share holographic icons for the application view
+ // (which is in both).
+ protected static PagedViewIconCache mPageViewIconCache = new PagedViewIconCache();
+
+ // If true, syncPages and syncPageItems will be called to refresh pages
+ protected boolean mContentIsRefreshable = true;
+
+ // If true, modify alpha of neighboring pages as user scrolls left/right
+ protected boolean mFadeInAdjacentScreens = true;
+
+ // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding
+ // to switch to a new page
+ protected boolean mUsePagingTouchSlop = true;
+
+ // If true, the subclass should directly update mScrollX itself in its computeScroll method
+ // (SmoothPagedView does this)
+ protected boolean mDeferScrollUpdate = false;
+
+ protected boolean mIsPageMoving = false;
+
+ public interface PageSwitchListener {
+ void onPageSwitch(View newPage, int newPageIndex);
+ }
+
+ public PagedView(Context context) {
+ this(context, null);
+ }
+
+ public PagedView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PagedView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mChoiceMode = CHOICE_MODE_NONE;
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.PagedView, defStyle, 0);
+ mPageSpacing = a.getDimensionPixelSize(R.styleable.PagedView_pageSpacing, 0);
+ mPageLayoutPaddingTop = a.getDimensionPixelSize(
+ R.styleable.PagedView_pageLayoutPaddingTop, 10);
+ mPageLayoutPaddingBottom = a.getDimensionPixelSize(
+ R.styleable.PagedView_pageLayoutPaddingBottom, 10);
+ mPageLayoutPaddingLeft = a.getDimensionPixelSize(
+ R.styleable.PagedView_pageLayoutPaddingLeft, 10);
+ mPageLayoutPaddingRight = a.getDimensionPixelSize(
+ R.styleable.PagedView_pageLayoutPaddingRight, 10);
+ mPageLayoutWidthGap = a.getDimensionPixelSize(
+ R.styleable.PagedView_pageLayoutWidthGap, -1);
+ mPageLayoutHeightGap = a.getDimensionPixelSize(
+ R.styleable.PagedView_pageLayoutHeightGap, -1);
+ a.recycle();
+
+ setHapticFeedbackEnabled(false);
+ init();
+ }
+
+ /**
+ * Initializes various states for this workspace.
+ */
+ protected void init() {
+ mDirtyPageContent = new ArrayList<Boolean>();
+ mDirtyPageContent.ensureCapacity(32);
+ mScroller = new Scroller(getContext(), new ScrollInterpolator());
+ mCurrentPage = 0;
+ mCenterPagesVertically = true;
+
+ final ViewConfiguration configuration = ViewConfiguration.get(getContext());
+ mTouchSlop = configuration.getScaledTouchSlop();
+ mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
+ mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
+ }
+
+ public void setPageSwitchListener(PageSwitchListener pageSwitchListener) {
+ mPageSwitchListener = pageSwitchListener;
+ if (mPageSwitchListener != null) {
+ mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
+ }
+ }
+
+ /**
+ * Returns the index of the currently displayed page.
+ *
+ * @return The index of the currently displayed page.
+ */
+ int getCurrentPage() {
+ return mCurrentPage;
+ }
+
+ int getPageCount() {
+ return getChildCount();
+ }
+
+ View getPageAt(int index) {
+ return getChildAt(index);
+ }
+
+ int getScrollWidth() {
+ return getWidth();
+ }
+
+ /**
+ * Updates the scroll of the current page immediately to its final scroll position. We use this
+ * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
+ * the previous tab page.
+ */
+ protected void updateCurrentPageScroll() {
+ int newX = getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage);
+ scrollTo(newX, 0);
+ mScroller.setFinalX(newX);
+ }
+
+ /**
+ * Sets the current page.
+ */
+ void setCurrentPage(int currentPage) {
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
+ // don't introduce any checks like mCurrentPage == currentPage here-- if we change the
+ // the default
+ if (getChildCount() == 0) {
+ return;
+ }
+
+ mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
+ updateCurrentPageScroll();
+ notifyPageSwitchListener();
+ invalidate();
+ }
+
+ protected void notifyPageSwitchListener() {
+ if (mPageSwitchListener != null) {
+ mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
+ }
+ }
+
+ private void pageBeginMoving() {
+ mIsPageMoving = true;
+ onPageBeginMoving();
+ }
+
+ private void pageEndMoving() {
+ onPageEndMoving();
+ mIsPageMoving = false;
+ }
+
+ // a method that subclasses can override to add behavior
+ protected void onPageBeginMoving() {
+ }
+
+ // a method that subclasses can override to add behavior
+ protected void onPageEndMoving() {
+ }
+
+ /**
+ * Registers the specified listener on each page contained in this workspace.
+ *
+ * @param l The listener used to respond to long clicks.
+ */
+ @Override
+ public void setOnLongClickListener(OnLongClickListener l) {
+ mLongClickListener = l;
+ final int count = getPageCount();
+ for (int i = 0; i < count; i++) {
+ getPageAt(i).setOnLongClickListener(l);
+ }
+ }
+
+ @Override
+ public void scrollBy(int x, int y) {
+ scrollTo(mUnboundedScrollX + x, mScrollY + y);
+ }
+
+ @Override
+ public void scrollTo(int x, int y) {
+ mUnboundedScrollX = x;
+
+ if (x < 0) {
+ super.scrollTo(0, y);
+ if (mAllowOverScroll) {
+ overScroll(x);
+ }
+ } else if (x > mMaxScrollX) {
+ super.scrollTo(mMaxScrollX, y);
+ if (mAllowOverScroll) {
+ overScroll(x - mMaxScrollX);
+ }
+ } else {
+ super.scrollTo(x, y);
+ }
+
+ mTouchX = x;
+ mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+ }
+
+ // we moved this functionality to a helper function so SmoothPagedView can reuse it
+ protected boolean computeScrollHelper() {
+ if (mScroller.computeScrollOffset()) {
+ mDirtyPageAlpha = true;
+ scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+ invalidate();
+ return true;
+ } else if (mNextPage != INVALID_PAGE) {
+ mDirtyPageAlpha = true;
+ mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
+ mNextPage = INVALID_PAGE;
+ notifyPageSwitchListener();
+ // We don't want to trigger a page end moving unless the page has settled
+ // and the user has stopped scrolling
+ if (mTouchState == TOUCH_STATE_REST) {
+ pageEndMoving();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void computeScroll() {
+ computeScrollHelper();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ if (widthMode != MeasureSpec.EXACTLY) {
+ throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
+ }
+
+ /* Allow the height to be set as WRAP_CONTENT. This allows the particular case
+ * of the All apps view on XLarge displays to not take up more space then it needs. Width
+ * is still not allowed to be set as WRAP_CONTENT since many parts of the code expect
+ * each page to have the same width.
+ */
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ int maxChildHeight = 0;
+
+ final int verticalPadding = mPaddingTop + mPaddingBottom;
+
+ // The children are given the same width and height as the workspace
+ // unless they were set to WRAP_CONTENT
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ // disallowing padding in paged view (just pass 0)
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+ int childWidthMode;
+ if (lp.width == LayoutParams.WRAP_CONTENT) {
+ childWidthMode = MeasureSpec.AT_MOST;
+ } else {
+ childWidthMode = MeasureSpec.EXACTLY;
+ }
+
+ int childHeightMode;
+ if (lp.height == LayoutParams.WRAP_CONTENT) {
+ childHeightMode = MeasureSpec.AT_MOST;
+ } else {
+ childHeightMode = MeasureSpec.EXACTLY;
+ }
+
+ final int childWidthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(widthSize, childWidthMode);
+ final int childHeightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode);
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
+ }
+
+ if (heightMode == MeasureSpec.AT_MOST) {
+ heightSize = maxChildHeight + verticalPadding;
+ }
+ if (childCount > 0) {
+ mMaxScrollX = getChildOffset(childCount - 1) - getRelativeChildOffset(childCount - 1);
+ } else {
+ mMaxScrollX = 0;
+ }
+
+ setMeasuredDimension(widthSize, heightSize);
+ }
+
+ protected void moveToNewPageWithoutMovingCellLayouts(int newCurrentPage) {
+ int newX = getChildOffset(newCurrentPage) - getRelativeChildOffset(newCurrentPage);
+ int delta = newX - mScrollX;
+
+ final int screenCount = getChildCount();
+ for (int i = 0; i < screenCount; i++) {
+ CellLayout cl = (CellLayout) getChildAt(i);
+ cl.setX(cl.getX() + delta);
+ }
+ setCurrentPage(newCurrentPage);
+ }
+
+ // A layout scale of 1.0f assumes that the CellLayouts, in their unshrunken state, have a
+ // scale of 1.0f. A layout scale of 0.8f assumes the CellLayouts have a scale of 0.8f, and
+ // tightens the layout accordingly
+ public void setLayoutScale(float childrenScale) {
+ mLayoutScale = childrenScale;
+
+ // Now we need to do a re-layout, but preserving absolute X and Y coordinates
+ int childCount = getChildCount();
+ float childrenX[] = new float[childCount];
+ float childrenY[] = new float[childCount];
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ childrenX[i] = child.getX();
+ childrenY[i] = child.getY();
+ }
+ onLayout(false, mLeft, mTop, mRight, mBottom);
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ child.setX(childrenX[i]);
+ child.setY(childrenY[i]);
+ }
+ // Also, the page offset has changed (since the pages are now smaller);
+ // update the page offset, but again preserving absolute X and Y coordinates
+ moveToNewPageWithoutMovingCellLayouts(mCurrentPage);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
+ setHorizontalScrollBarEnabled(false);
+ int newX = getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage);
+ scrollTo(newX, 0);
+ mScroller.setFinalX(newX);
+ setHorizontalScrollBarEnabled(true);
+ mFirstLayout = false;
+ }
+
+ final int verticalPadding = mPaddingTop + mPaddingBottom;
+ final int childCount = getChildCount();
+ int childLeft = 0;
+ if (childCount > 0) {
+ childLeft = getRelativeChildOffset(0);
+ }
+
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE) {
+ final int childWidth = getScaledMeasuredWidth(child);
+ final int childHeight = child.getMeasuredHeight();
+ int childTop = mPaddingTop;
+ if (mCenterPagesVertically) {
+ childTop += ((getMeasuredHeight() - verticalPadding) - childHeight) / 2;
+ }
+
+ child.layout(childLeft, childTop,
+ childLeft + child.getMeasuredWidth(), childTop + childHeight);
+ childLeft += childWidth + mPageSpacing;
+ }
+ }
+ if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
+ mFirstLayout = false;
+ }
+ }
+
+ protected void updateAdjacentPagesAlpha() {
+ if (mFadeInAdjacentScreens) {
+ if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) {
+ int halfScreenSize = getMeasuredWidth() / 2;
+ int screenCenter = mScrollX + halfScreenSize;
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ View layout = (View) getChildAt(i);
+ int childWidth = getScaledMeasuredWidth(layout);
+ int halfChildWidth = (childWidth / 2);
+ int childCenter = getChildOffset(i) + halfChildWidth;
+
+ // On the first layout, we may not have a width nor a proper offset, so for now
+ // we should just assume full page width (and calculate the offset according to
+ // that).
+ if (childWidth <= 0) {
+ childWidth = getMeasuredWidth();
+ childCenter = (i * childWidth) + (childWidth / 2);
+ }
+
+ int d = halfChildWidth;
+ int distanceFromScreenCenter = childCenter - screenCenter;
+ if (distanceFromScreenCenter > 0) {
+ if (i > 0) {
+ d += getScaledMeasuredWidth(getChildAt(i - 1)) / 2;
+ }
+ } else {
+ if (i < childCount - 1) {
+ d += getScaledMeasuredWidth(getChildAt(i + 1)) / 2;
+ }
+ }
+ d += mPageSpacing;
+
+ // Preventing potential divide-by-zero
+ d = Math.max(1, d);
+
+ float dimAlpha = (float) (Math.abs(distanceFromScreenCenter)) / d;
+ dimAlpha = Math.max(0.0f, Math.min(1.0f, (dimAlpha * dimAlpha)));
+ float alpha = 1.0f - dimAlpha;
+
+ if (alpha < ALPHA_QUANTIZE_LEVEL) {
+ alpha = 0.0f;
+ } else if (alpha > 1.0f - ALPHA_QUANTIZE_LEVEL) {
+ alpha = 1.0f;
+ }
+
+ if (Float.compare(alpha, layout.getAlpha()) != 0) {
+ layout.setAlpha(alpha);
+ }
+ }
+ mDirtyPageAlpha = false;
+ }
+ }
+ }
+
+ protected void screenScrolled(int screenCenter) {
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ int halfScreenSize = getMeasuredWidth() / 2;
+ int screenCenter = mScrollX + halfScreenSize;
+
+ if (screenCenter != mLastScreenCenter) {
+ screenScrolled(screenCenter);
+ updateAdjacentPagesAlpha();
+ mLastScreenCenter = screenCenter;
+ }
+
+ // Find out which screens are visible; as an optimization we only call draw on them
+ // As an optimization, this code assumes that all pages have the same width as the 0th
+ // page.
+ final int pageCount = getChildCount();
+ if (pageCount > 0) {
+ final int pageWidth = getScaledMeasuredWidth(getChildAt(0));
+ final int screenWidth = getMeasuredWidth();
+ int x = getRelativeChildOffset(0) + pageWidth;
+ int leftScreen = 0;
+ int rightScreen = 0;
+ while (x <= mScrollX) {
+ leftScreen++;
+ x += getScaledMeasuredWidth(getChildAt(leftScreen)) + mPageSpacing;
+ }
+ rightScreen = leftScreen;
+ while (x < mScrollX + screenWidth && rightScreen < pageCount) {
+ rightScreen++;
+ if (rightScreen < pageCount) {
+ x += getScaledMeasuredWidth(getChildAt(rightScreen)) + mPageSpacing;
+ }
+ }
+ rightScreen = Math.min(getChildCount() - 1, rightScreen);
+
+ final long drawingTime = getDrawingTime();
+ // Clip to the bounds
+ canvas.save();
+ canvas.clipRect(mScrollX, mScrollY, mScrollX + mRight - mLeft,
+ mScrollY + mBottom - mTop);
+
+ for (int i = leftScreen; i <= rightScreen; i++) {
+ drawChild(canvas, getChildAt(i), drawingTime);
+ }
+ canvas.restore();
+ }
+ }
+
+ @Override
+ public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
+ int page = indexOfChild(child);
+ if (page != mCurrentPage || !mScroller.isFinished()) {
+ snapToPage(page);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+ int focusablePage;
+ if (mNextPage != INVALID_PAGE) {
+ focusablePage = mNextPage;
+ } else {
+ focusablePage = mCurrentPage;
+ }
+ View v = getPageAt(focusablePage);
+ if (v != null) {
+ v.requestFocus(direction, previouslyFocusedRect);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean dispatchUnhandledMove(View focused, int direction) {
+ if (direction == View.FOCUS_LEFT) {
+ if (getCurrentPage() > 0) {
+ snapToPage(getCurrentPage() - 1);
+ return true;
+ }
+ } else if (direction == View.FOCUS_RIGHT) {
+ if (getCurrentPage() < getPageCount() - 1) {
+ snapToPage(getCurrentPage() + 1);
+ return true;
+ }
+ }
+ return super.dispatchUnhandledMove(focused, direction);
+ }
+
+ @Override
+ public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+ if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) {
+ getPageAt(mCurrentPage).addFocusables(views, direction);
+ }
+ if (direction == View.FOCUS_LEFT) {
+ if (mCurrentPage > 0) {
+ getPageAt(mCurrentPage - 1).addFocusables(views, direction);
+ }
+ } else if (direction == View.FOCUS_RIGHT){
+ if (mCurrentPage < getPageCount() - 1) {
+ getPageAt(mCurrentPage + 1).addFocusables(views, direction);
+ }
+ }
+ }
+
+ /**
+ * If one of our descendant views decides that it could be focused now, only
+ * pass that along if it's on the current page.
+ *
+ * This happens when live folders requery, and if they're off page, they
+ * end up calling requestFocus, which pulls it on page.
+ */
+ @Override
+ public void focusableViewAvailable(View focused) {
+ View current = getPageAt(mCurrentPage);
+ View v = focused;
+ while (true) {
+ if (v == current) {
+ super.focusableViewAvailable(focused);
+ return;
+ }
+ if (v == this) {
+ return;
+ }
+ ViewParent parent = v.getParent();
+ if (parent instanceof View) {
+ v = (View)v.getParent();
+ } else {
+ return;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ if (disallowIntercept) {
+ // We need to make sure to cancel our long press if
+ // a scrollable widget takes over touch events
+ final View currentPage = getChildAt(mCurrentPage);
+ currentPage.cancelLongPress();
+ }
+ super.requestDisallowInterceptTouchEvent(disallowIntercept);
+ }
+
+ /**
+ * Return true if a tap at (x, y) should trigger a flip to the previous page.
+ */
+ protected boolean hitsPreviousPage(float x, float y) {
+ return (x < getRelativeChildOffset(mCurrentPage) - mPageSpacing);
+ }
+
+ /**
+ * Return true if a tap at (x, y) should trigger a flip to the next page.
+ */
+ protected boolean hitsNextPage(float x, float y) {
+ return (x > (getMeasuredWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ /*
+ * This method JUST determines whether we want to intercept the motion.
+ * If we return true, onTouchEvent will be called and we do the actual
+ * scrolling there.
+ */
+
+ // Skip touch handling if there are no pages to swipe
+ if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev);
+
+ /*
+ * Shortcut the most recurring case: the user is in the dragging
+ * state and he is moving his finger. We want to intercept this
+ * motion.
+ */
+ final int action = ev.getAction();
+ if ((action == MotionEvent.ACTION_MOVE) &&
+ (mTouchState == TOUCH_STATE_SCROLLING)) {
+ return true;
+ }
+
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_MOVE: {
+ /*
+ * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
+ * whether the user has moved far enough from his original down touch.
+ */
+ if (mActivePointerId != INVALID_POINTER) {
+ determineScrollingStart(ev);
+ break;
+ }
+ // if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
+ // event. in that case, treat the first occurence of a move event as a ACTION_DOWN
+ // i.e. fall through to the next case (don't break)
+ // (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
+ // while it's small- this was causing a crash before we checked for INVALID_POINTER)
+ }
+
+ case MotionEvent.ACTION_DOWN: {
+ final float x = ev.getX();
+ final float y = ev.getY();
+ // Remember location of down touch
+ mDownMotionX = x;
+ mLastMotionX = x;
+ mLastMotionY = y;
+ mActivePointerId = ev.getPointerId(0);
+ mAllowLongPress = true;
+
+ /*
+ * If being flinged and user touches the screen, initiate drag;
+ * otherwise don't. mScroller.isFinished should be false when
+ * being flinged.
+ */
+ final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
+ final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
+ if (finishedScrolling) {
+ mTouchState = TOUCH_STATE_REST;
+ mScroller.abortAnimation();
+ } else {
+ mTouchState = TOUCH_STATE_SCROLLING;
+ }
+
+ // check if this can be the beginning of a tap on the side of the pages
+ // to scroll the current page
+ if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) {
+ if (getChildCount() > 0) {
+ if (hitsPreviousPage(x, y)) {
+ mTouchState = TOUCH_STATE_PREV_PAGE;
+ } else if (hitsNextPage(x, y)) {
+ mTouchState = TOUCH_STATE_NEXT_PAGE;
+ }
+ }
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_UP:
+ onWallpaperTap(ev);
+ case MotionEvent.ACTION_CANCEL:
+ mTouchState = TOUCH_STATE_REST;
+ mAllowLongPress = false;
+ mActivePointerId = INVALID_POINTER;
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ onSecondaryPointerUp(ev);
+ break;
+ }
+
+ /*
+ * The only time we want to intercept motion events is if we are in the
+ * drag mode.
+ */
+ return mTouchState != TOUCH_STATE_REST;
+ }
+
+ protected void animateClickFeedback(View v, final Runnable r) {
+ // animate the view slightly to show click feedback running some logic after it is "pressed"
+ Animation anim = AnimationUtils.loadAnimation(getContext(),
+ R.anim.paged_view_click_feedback);
+ anim.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {}
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ r.run();
+ }
+ @Override
+ public void onAnimationEnd(Animation animation) {}
+ });
+ v.startAnimation(anim);
+ }
+
+ /*
+ * Determines if we should change the touch state to start scrolling after the
+ * user moves their touch point too far.
+ */
+ protected void determineScrollingStart(MotionEvent ev) {
+ /*
+ * Locally do absolute value. mLastMotionX is set to the y value
+ * of the down event.
+ */
+ final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ final float x = ev.getX(pointerIndex);
+ final float y = ev.getY(pointerIndex);
+ final int xDiff = (int) Math.abs(x - mLastMotionX);
+ final int yDiff = (int) Math.abs(y - mLastMotionY);
+
+ final int touchSlop = mTouchSlop;
+ boolean xPaged = xDiff > mPagingTouchSlop;
+ boolean xMoved = xDiff > touchSlop;
+ boolean yMoved = yDiff > touchSlop;
+
+ if (xMoved || yMoved) {
+ if (mUsePagingTouchSlop ? xPaged : xMoved) {
+ // Scroll if the user moved far enough along the X axis
+ mTouchState = TOUCH_STATE_SCROLLING;
+ mLastMotionX = x;
+ mTouchX = mScrollX;
+ mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+ pageBeginMoving();
+ }
+ // Either way, cancel any pending longpress
+ if (mAllowLongPress) {
+ mAllowLongPress = false;
+ // Try canceling the long press. It could also have been scheduled
+ // by a distant descendant, so use the mAllowLongPress flag to block
+ // everything
+ final View currentPage = getPageAt(mCurrentPage);
+ if (currentPage != null) {
+ currentPage.cancelLongPress();
+ }
+ }
+ }
+ }
+
+ // This curve determines how the effect of scrolling over the limits of the page dimishes
+ // as the user pulls further and further from the bounds
+ private float overScrollInfluenceCurve(float f) {
+ f -= 1.0f;
+ return f * f * f + 1.0f;
+ }
+
+ protected void overScroll(float amount) {
+ int screenSize = getMeasuredWidth();
+
+ float f = (amount / screenSize);
+
+ if (f == 0) return;
+ f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+
+ int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
+ if (amount < 0) {
+ mScrollX = overScrollAmount;
+ } else {
+ mScrollX = mMaxScrollX + overScrollAmount;
+ }
+ invalidate();
+ }
+
+ protected float maxOverScroll() {
+ // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not
+ // exceed). Used to find out how much extra wallpaper we need for the overscroll effect
+ float f = 1.0f;
+ f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
+ return OVERSCROLL_DAMP_FACTOR * f;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // Skip touch handling if there are no pages to swipe
+ if (getChildCount() <= 0) return super.onTouchEvent(ev);
+
+ acquireVelocityTrackerAndAddMovement(ev);
+
+ final int action = ev.getAction();
+
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ /*
+ * If being flinged and user touches, stop the fling. isFinished
+ * will be false if being flinged.
+ */
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
+
+ // Remember where the motion event started
+ mDownMotionX = mLastMotionX = ev.getX();
+ mActivePointerId = ev.getPointerId(0);
+ if (mTouchState == TOUCH_STATE_SCROLLING) {
+ pageBeginMoving();
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ if (mTouchState == TOUCH_STATE_SCROLLING) {
+ // Scroll to follow the motion event
+ final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ final float x = ev.getX(pointerIndex);
+ final int deltaX = (int) (mLastMotionX - x);
+ mLastMotionX = x;
+
+ if (deltaX != 0) {
+ mTouchX += deltaX;
+ mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+ if (!mDeferScrollUpdate) {
+ scrollBy(deltaX, 0);
+ } else {
+ invalidate();
+ }
+ } else {
+ awakenScrollBars();
+ }
+ } else {
+ determineScrollingStart(ev);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ if (mTouchState == TOUCH_STATE_SCROLLING) {
+ final int activePointerId = mActivePointerId;
+ final int pointerIndex = ev.findPointerIndex(activePointerId);
+ final float x = ev.getX(pointerIndex);
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+ int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
+ final int deltaX = (int) (x - mDownMotionX);
+ boolean isfling = Math.abs(deltaX) > MIN_LENGTH_FOR_FLING;
+ boolean isSignificantMove = Math.abs(deltaX) > MIN_LENGTH_FOR_MOVE;
+
+ final int snapVelocity = mSnapVelocity;
+ if ((isSignificantMove && deltaX > 0 ||
+ (isfling && velocityX > snapVelocity)) && mCurrentPage > 0) {
+ snapToPageWithVelocity(mCurrentPage - 1, velocityX);
+ } else if ((isSignificantMove && deltaX < 0 ||
+ (isfling && velocityX < -snapVelocity)) &&
+ mCurrentPage < getChildCount() - 1) {
+ snapToPageWithVelocity(mCurrentPage + 1, velocityX);
+ } else {
+ snapToDestination();
+ }
+ } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
+ // at this point we have not moved beyond the touch slop
+ // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
+ // we can just page
+ int nextPage = Math.max(0, mCurrentPage - 1);
+ if (nextPage != mCurrentPage) {
+ snapToPage(nextPage);
+ } else {
+ snapToDestination();
+ }
+ } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
+ // at this point we have not moved beyond the touch slop
+ // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
+ // we can just page
+ int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
+ if (nextPage != mCurrentPage) {
+ snapToPage(nextPage);
+ } else {
+ snapToDestination();
+ }
+ } else {
+ onWallpaperTap(ev);
+ }
+ mTouchState = TOUCH_STATE_REST;
+ mActivePointerId = INVALID_POINTER;
+ releaseVelocityTracker();
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ if (mTouchState == TOUCH_STATE_SCROLLING) {
+ snapToDestination();
+ }
+ mTouchState = TOUCH_STATE_REST;
+ mActivePointerId = INVALID_POINTER;
+ releaseVelocityTracker();
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ onSecondaryPointerUp(ev);
+ break;
+ }
+
+ return true;
+ }
+
+ private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+ }
+
+ private void releaseVelocityTracker() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+
+ private void onSecondaryPointerUp(MotionEvent ev) {
+ final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
+ MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ final int pointerId = ev.getPointerId(pointerIndex);
+ if (pointerId == mActivePointerId) {
+ // This was our active pointer going up. Choose a new
+ // active pointer and adjust accordingly.
+ // TODO: Make this decision more intelligent.
+ final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+ mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
+ mLastMotionY = ev.getY(newPointerIndex);
+ mActivePointerId = ev.getPointerId(newPointerIndex);
+ if (mVelocityTracker != null) {
+ mVelocityTracker.clear();
+ }
+ }
+ if (mTouchState == TOUCH_STATE_REST) {
+ onWallpaperTap(ev);
+ }
+ }
+
+ protected void onWallpaperTap(MotionEvent ev) {
+ }
+
+ @Override
+ public void requestChildFocus(View child, View focused) {
+ super.requestChildFocus(child, focused);
+ int page = indexOfChild(child);
+ if (page >= 0 && !isInTouchMode()) {
+ snapToPage(page);
+ }
+ }
+
+ protected int getChildIndexForRelativeOffset(int relativeOffset) {
+ final int childCount = getChildCount();
+ int left;
+ int right;
+ for (int i = 0; i < childCount; ++i) {
+ left = getRelativeChildOffset(i);
+ right = (left + getScaledMeasuredWidth(getChildAt(i)));
+ if (left <= relativeOffset && relativeOffset <= right) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ protected int getRelativeChildOffset(int index) {
+ return (getMeasuredWidth() - getChildAt(index).getMeasuredWidth()) / 2;
+ }
+
+ protected int getChildOffset(int index) {
+ if (getChildCount() == 0)
+ return 0;
+
+ int offset = getRelativeChildOffset(0);
+ for (int i = 0; i < index; ++i) {
+ offset += getScaledMeasuredWidth(getChildAt(i)) + mPageSpacing;
+ }
+ return offset;
+ }
+
+ protected int getScaledMeasuredWidth(View child) {
+ return (int) (child.getMeasuredWidth() * mLayoutScale + 0.5f);
+ }
+
+ int getPageNearestToCenterOfScreen() {
+ int minDistanceFromScreenCenter = getMeasuredWidth();
+ int minDistanceFromScreenCenterIndex = -1;
+ int screenCenter = mScrollX + (getMeasuredWidth() / 2);
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ View layout = (View) getChildAt(i);
+ int childWidth = getScaledMeasuredWidth(layout);
+ int halfChildWidth = (childWidth / 2);
+ int childCenter = getChildOffset(i) + halfChildWidth;
+ int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
+ if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
+ minDistanceFromScreenCenter = distanceFromScreenCenter;
+ minDistanceFromScreenCenterIndex = i;
+ }
+ }
+ return minDistanceFromScreenCenterIndex;
+ }
+
+ protected void snapToDestination() {
+ snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
+ }
+
+ private static class ScrollInterpolator implements Interpolator {
+ public ScrollInterpolator() {
+ }
+
+ public float getInterpolation(float t) {
+ t -= 1.0f;
+ return t*t*t*t*t + 1;
+ }
+ }
+
+ // We want the duration of the page snap animation to be influenced by the distance that
+ // the screen has to travel, however, we don't want this duration to be effected in a
+ // purely linear fashion. Instead, we use this method to moderate the effect that the distance
+ // of travel has on the overall snap duration.
+ float distanceInfluenceForSnapDuration(float f) {
+ f -= 0.5f; // center the values about 0.
+ f *= 0.3f * Math.PI / 2.0f;
+ return (float) Math.sin(f);
+ }
+
+ protected void snapToPageWithVelocity(int whichPage, int velocity) {
+ whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
+ int halfScreenSize = getMeasuredWidth() / 2;
+
+ final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
+ int delta = newX - mUnboundedScrollX;
+ int duration = 0;
+
+ if (Math.abs(velocity) < MIN_FLING_VELOCITY) {
+ // If the velocity is low enough, then treat this more as an automatic page advance
+ // as opposed to an apparent physical response to flinging
+ snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
+ return;
+ }
+
+ // Here we compute a "distance" that will be used in the computation of the overall
+ // snap duration. This is a function of the actual distance that needs to be traveled;
+ // we keep this value close to half screen size in order to reduce the variance in snap
+ // duration as a function of the distance the page needs to travel.
+ float distanceRatio = 1.0f * Math.abs(delta) / 2 * halfScreenSize;
+ float distance = halfScreenSize + halfScreenSize *
+ distanceInfluenceForSnapDuration(distanceRatio);
+
+ velocity = Math.abs(velocity);
+ velocity = Math.max(MINIMUM_SNAP_VELOCITY, velocity);
+
+ // we want the page's snap velocity to approximately match the velocity at which the
+ // user flings, so we scale the duration by a value near to the derivative of the scroll
+ // interpolator at zero, ie. 5. We use 6 to make it a little slower.
+ duration = 6 * Math.round(1000 * Math.abs(distance / velocity));
+
+ snapToPage(whichPage, delta, duration);
+ }
+
+ protected void snapToPage(int whichPage) {
+ snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
+ }
+
+ protected void snapToPage(int whichPage, int duration) {
+ whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
+
+ int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
+ final int sX = mUnboundedScrollX;
+ final int delta = newX - sX;
+ snapToPage(whichPage, delta, duration);
+ }
+
+ protected void snapToPage(int whichPage, int delta, int duration) {
+ mNextPage = whichPage;
+
+ View focusedChild = getFocusedChild();
+ if (focusedChild != null && whichPage != mCurrentPage &&
+ focusedChild == getChildAt(mCurrentPage)) {
+ focusedChild.clearFocus();
+ }
+
+ pageBeginMoving();
+ awakenScrollBars(duration);
+ if (duration == 0) {
+ duration = Math.abs(delta);
+ }
+
+ if (!mScroller.isFinished()) mScroller.abortAnimation();
+ mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
+
+ // only load some associated pages
+ loadAssociatedPages(mNextPage);
+ notifyPageSwitchListener();
+ invalidate();
+ }
+
+ public void scrollLeft() {
+ if (mScroller.isFinished()) {
+ if (mCurrentPage > 0) snapToPage(mCurrentPage - 1);
+ } else {
+ if (mNextPage > 0) snapToPage(mNextPage - 1);
+ }
+ }
+
+ public void scrollRight() {
+ if (mScroller.isFinished()) {
+ if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1);
+ } else {
+ if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1);
+ }
+ }
+
+ public int getPageForView(View v) {
+ int result = -1;
+ if (v != null) {
+ ViewParent vp = v.getParent();
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ if (vp == getChildAt(i)) {
+ return i;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return True is long presses are still allowed for the current touch
+ */
+ public boolean allowLongPress() {
+ return mAllowLongPress;
+ }
+
+ /**
+ * Set true to allow long-press events to be triggered, usually checked by
+ * {@link Launcher} to accept or block dpad-initiated long-presses.
+ */
+ public void setAllowLongPress(boolean allowLongPress) {
+ mAllowLongPress = allowLongPress;
+ }
+
+ public static class SavedState extends BaseSavedState {
+ int currentPage = -1;
+
+ SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ private SavedState(Parcel in) {
+ super(in);
+ currentPage = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ super.writeToParcel(out, flags);
+ out.writeInt(currentPage);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+ public void loadAssociatedPages(int page) {
+ if (mContentIsRefreshable) {
+ final int count = getChildCount();
+ if (page < count) {
+ int lowerPageBound = getAssociatedLowerPageBound(page);
+ int upperPageBound = getAssociatedUpperPageBound(page);
+ for (int i = 0; i < count; ++i) {
+ final ViewGroup layout = (ViewGroup) getChildAt(i);
+ final int childCount = layout.getChildCount();
+ if (lowerPageBound <= i && i <= upperPageBound) {
+ if (mDirtyPageContent.get(i)) {
+ syncPageItems(i);
+ mDirtyPageContent.set(i, false);
+ }
+ } else {
+ if (childCount > 0) {
+ layout.removeAllViews();
+ }
+ mDirtyPageContent.set(i, true);
+ }
+ }
+ }
+ }
+ }
+
+ protected int getAssociatedLowerPageBound(int page) {
+ return Math.max(0, page - 1);
+ }
+ protected int getAssociatedUpperPageBound(int page) {
+ final int count = getChildCount();
+ return Math.min(page + 1, count - 1);
+ }
+
+ protected void startChoiceMode(int mode, ActionMode.Callback callback) {
+ if (isChoiceMode(CHOICE_MODE_NONE)) {
+ mChoiceMode = mode;
+ mActionMode = startActionMode(callback);
+ }
+ }
+
+ public void endChoiceMode() {
+ if (!isChoiceMode(CHOICE_MODE_NONE)) {
+ mChoiceMode = CHOICE_MODE_NONE;
+ resetCheckedGrandchildren();
+ if (mActionMode != null) mActionMode.finish();
+ mActionMode = null;
+ }
+ }
+
+ protected boolean isChoiceMode(int mode) {
+ return mChoiceMode == mode;
+ }
+
+ protected ArrayList<Checkable> getCheckedGrandchildren() {
+ ArrayList<Checkable> checked = new ArrayList<Checkable>();
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ final ViewGroup layout = (ViewGroup) getChildAt(i);
+ final int grandChildCount = layout.getChildCount();
+ for (int j = 0; j < grandChildCount; ++j) {
+ final View v = layout.getChildAt(j);
+ if (v instanceof Checkable && ((Checkable) v).isChecked()) {
+ checked.add((Checkable) v);
+ }
+ }
+ }
+ return checked;
+ }
+
+ /**
+ * If in CHOICE_MODE_SINGLE and an item is checked, returns that item.
+ * Otherwise, returns null.
+ */
+ protected Checkable getSingleCheckedGrandchild() {
+ if (mChoiceMode == CHOICE_MODE_SINGLE) {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; ++i) {
+ final ViewGroup layout = (ViewGroup) getChildAt(i);
+ final int grandChildCount = layout.getChildCount();
+ for (int j = 0; j < grandChildCount; ++j) {
+ final View v = layout.getChildAt(j);
+ if (v instanceof Checkable && ((Checkable) v).isChecked()) {
+ return (Checkable) v;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public Object getChosenItem() {
+ View checkedView = (View) getSingleCheckedGrandchild();
+ if (checkedView != null) {
+ return checkedView.getTag();
+ }
+ return null;
+ }
+
+ protected void resetCheckedGrandchildren() {
+ // loop through children, and set all of their children to _not_ be checked
+ final ArrayList<Checkable> checked = getCheckedGrandchildren();
+ for (int i = 0; i < checked.size(); ++i) {
+ final Checkable c = checked.get(i);
+ c.setChecked(false);
+ }
+ }
+
+ public void setRestorePage(int restorePage) {
+ mRestorePage = restorePage;
+ }
+
+ /**
+ * This method is called ONLY to synchronize the number of pages that the paged view has.
+ * To actually fill the pages with information, implement syncPageItems() below. It is
+ * guaranteed that syncPageItems() will be called for a particular page before it is shown,
+ * and therefore, individual page items do not need to be updated in this method.
+ */
+ public abstract void syncPages();
+
+ /**
+ * This method is called to synchronize the items that are on a particular page. If views on
+ * the page can be reused, then they should be updated within this method.
+ */
+ public abstract void syncPageItems(int page);
+
+ public void invalidatePageData() {
+ if (mContentIsRefreshable) {
+ // Update all the pages
+ syncPages();
+
+ // Mark each of the pages as dirty
+ final int count = getChildCount();
+ mDirtyPageContent.clear();
+ for (int i = 0; i < count; ++i) {
+ mDirtyPageContent.add(true);
+ }
+
+ // Use the restore page if necessary
+ if (mRestorePage > -1) {
+ mCurrentPage = mRestorePage;
+ mRestorePage = -1;
+ }
+
+ // Load any pages that are necessary for the current window of views
+ loadAssociatedPages(mCurrentPage);
+ mDirtyPageAlpha = true;
+ updateAdjacentPagesAlpha();
+ requestLayout();
+ }
+ }
+}
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
new file mode 100644
index 0000000..70ad997
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+
+/**
+ * An abstraction of the original CellLayout which supports laying out items
+ * which span multiple cells into a grid-like layout. Also supports dimming
+ * to give a preview of its contents.
+ */
+public class PagedViewCellLayout extends ViewGroup {
+ static final String TAG = "PagedViewCellLayout";
+
+ private float mHolographicAlpha;
+
+ private boolean mCenterContent;
+
+ private int mCellCountX;
+ private int mCellCountY;
+ private int mCellWidth;
+ private int mCellHeight;
+ private int mWidthGap;
+ private int mHeightGap;
+ private static int sDefaultCellDimensions = 96;
+
+ public PagedViewCellLayout(Context context) {
+ this(context, null);
+ }
+
+ public PagedViewCellLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PagedViewCellLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ setAlwaysDrawnWithCacheEnabled(false);
+
+ // setup default cell parameters
+ mCellWidth = mCellHeight = sDefaultCellDimensions;
+ mCellCountX = LauncherModel.getCellCountX();
+ mCellCountY = LauncherModel.getCellCountY();
+ mHolographicAlpha = 0.0f;
+ mWidthGap = mHeightGap = -1;
+ }
+
+ @Override
+ protected boolean onSetAlpha(int alpha) {
+ return true;
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ mHolographicAlpha = 1.0f - alpha;
+ setChildrenAlpha(alpha);
+ super.setAlpha(alpha);
+ }
+
+ @Override
+ public void cancelLongPress() {
+ super.cancelLongPress();
+
+ // Cancel long press for all children
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ child.cancelLongPress();
+ }
+ }
+
+ public boolean addViewToCellLayout(View child, int index, int childId,
+ PagedViewCellLayout.LayoutParams params) {
+ final PagedViewCellLayout.LayoutParams lp = params;
+
+ // Generate an id for each view, this assumes we have at most 256x256 cells
+ // per workspace screen
+ if (lp.cellX >= 0 && lp.cellX <= (mCellCountX - 1) &&
+ lp.cellY >= 0 && (lp.cellY <= mCellCountY - 1)) {
+ // If the horizontal or vertical span is set to -1, it is taken to
+ // mean that it spans the extent of the CellLayout
+ if (lp.cellHSpan < 0) lp.cellHSpan = mCellCountX;
+ if (lp.cellVSpan < 0) lp.cellVSpan = mCellCountY;
+
+ child.setId(childId);
+
+ // We might be in the middle or end of shrinking/fading to a dimmed view
+ // Make sure this view's alpha is set the same as all the rest of the views
+ child.setAlpha(1.0f - mHolographicAlpha);
+
+ addView(child, index, lp);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void requestChildFocus(View child, View focused) {
+ super.requestChildFocus(child, focused);
+ if (child != null) {
+ Rect r = new Rect();
+ child.getDrawingRect(r);
+ requestRectangleOnScreen(r);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // TODO: currently ignoring padding
+
+ int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+
+ int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+ int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+
+ if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
+ throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
+ }
+
+ final int cellWidth = mCellWidth;
+ final int cellHeight = mCellHeight;
+
+ int numWidthGaps = mCellCountX - 1;
+ int numHeightGaps = mCellCountY - 1;
+
+ int vSpaceLeft = heightSpecSize - mPaddingTop
+ - mPaddingBottom - (cellHeight * mCellCountY);
+ int heightGap = vSpaceLeft / numHeightGaps;
+
+ int hSpaceLeft = widthSpecSize - mPaddingLeft
+ - mPaddingRight - (cellWidth * mCellCountX);
+ int widthGap = hSpaceLeft / numWidthGaps;
+
+ // center it around the min gaps
+ int minGap = Math.min(widthGap, heightGap);
+ int paddingLeft = mPaddingLeft;
+ int paddingTop = mPaddingTop;
+ /*
+ if (minGap < heightGap) {
+ // vertical space has shrunken, so change padding accordingly
+ paddingTop += ((heightGap - minGap) * (mCellCountY - 1)) / 2;
+ } else if (minGap < widthGap) {
+ // horizontal space has shrunken, so change padding accordingly
+ paddingLeft += ((widthGap - minGap) * (mCellCountX - 1)) / 2;
+ }
+ */
+ if (mWidthGap > -1 && mHeightGap > -1) {
+ widthGap = mWidthGap;
+ heightGap = mHeightGap;
+ } else {
+ widthGap = heightGap = minGap;
+ }
+
+ int newWidth = mPaddingLeft + mPaddingRight + (mCellCountX * cellWidth) +
+ ((mCellCountX - 1) * widthGap);
+ int newHeight = mPaddingTop + mPaddingBottom + (mCellCountY * cellHeight) +
+ ((mCellCountY - 1) * heightGap);
+
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ PagedViewCellLayout.LayoutParams lp =
+ (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
+ lp.setup(cellWidth, cellHeight, widthGap, heightGap,
+ paddingLeft, paddingTop);
+
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
+ MeasureSpec.EXACTLY);
+ int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
+ MeasureSpec.EXACTLY);
+
+ child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+ }
+
+ setMeasuredDimension(newWidth, newHeight);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int count = getChildCount();
+
+ int offsetX = 0;
+ if (mCenterContent) {
+ // determine the max width of all the rows and center accordingly
+ int maxRowWidth = 0;
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ PagedViewCellLayout.LayoutParams lp =
+ (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
+ maxRowWidth = Math.max(maxRowWidth, lp.x + lp.width);
+ }
+ }
+ offsetX = (getMeasuredWidth() / 2) - (maxRowWidth / 2);
+ }
+
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ PagedViewCellLayout.LayoutParams lp =
+ (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
+
+ int childLeft = offsetX + lp.x;
+ int childTop = lp.y;
+ child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
+ }
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ return super.onTouchEvent(event) || true;
+ }
+
+ public void enableCenteredContent(boolean enabled) {
+ mCenterContent = enabled;
+ }
+
+ @Override
+ protected void setChildrenDrawingCacheEnabled(boolean enabled) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View view = getChildAt(i);
+ view.setDrawingCacheEnabled(enabled);
+ // Update the drawing caches
+ if (!view.isHardwareAccelerated()) {
+ view.buildDrawingCache(true);
+ }
+ }
+ }
+
+ public void setCellCount(int xCount, int yCount) {
+ mCellCountX = xCount;
+ mCellCountY = yCount;
+ requestLayout();
+ }
+
+ public void setGap(int widthGap, int heightGap) {
+ mWidthGap = widthGap;
+ mHeightGap = heightGap;
+ }
+
+ public void setCellDimensions(int width, int height) {
+ mCellWidth = width;
+ mCellHeight = height;
+ requestLayout();
+ }
+
+ public int getDefaultCellDimensions() {
+ return sDefaultCellDimensions;
+ }
+
+ private void setChildrenAlpha(float alpha) {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ getChildAt(i).setAlpha(alpha);
+ }
+ }
+
+ public int[] getCellCountForDimensions(int width, int height) {
+ // Always assume we're working with the smallest span to make sure we
+ // reserve enough space in both orientations
+ int smallerSize = Math.min(mCellWidth, mCellHeight);
+
+ // Always round up to next largest cell
+ int spanX = (width + smallerSize) / smallerSize;
+ int spanY = (height + smallerSize) / smallerSize;
+
+ return new int[] { spanX, spanY };
+ }
+
+ /**
+ * Start dragging the specified child
+ *
+ * @param child The child that is being dragged
+ */
+ void onDragChild(View child) {
+ PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
+ lp.isDragging = true;
+ }
+
+ /**
+ * Estimates the number of cells that the specified width would take up.
+ */
+ public int estimateCellHSpan(int width) {
+ // TODO: we need to take widthGap into effect
+ return (width + mCellWidth) / mCellWidth;
+ }
+
+ /**
+ * Estimates the number of cells that the specified height would take up.
+ */
+ public int estimateCellVSpan(int height) {
+ // TODO: we need to take heightGap into effect
+ return (height + mCellHeight) / mCellHeight;
+ }
+
+ /**
+ * Estimates the width that the number of vSpan cells will take up.
+ */
+ public int estimateCellWidth(int hSpan) {
+ // TODO: we need to take widthGap into effect
+ return hSpan * mCellWidth;
+ }
+
+ /**
+ * Estimates the height that the number of vSpan cells will take up.
+ */
+ public int estimateCellHeight(int vSpan) {
+ // TODO: we need to take heightGap into effect
+ return vSpan * mCellHeight;
+ }
+
+ @Override
+ public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
+ }
+
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ return p instanceof PagedViewCellLayout.LayoutParams;
+ }
+
+ @Override
+ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+ return new PagedViewCellLayout.LayoutParams(p);
+ }
+
+ public static class LayoutParams extends ViewGroup.MarginLayoutParams {
+ /**
+ * Horizontal location of the item in the grid.
+ */
+ @ViewDebug.ExportedProperty
+ public int cellX;
+
+ /**
+ * Vertical location of the item in the grid.
+ */
+ @ViewDebug.ExportedProperty
+ public int cellY;
+
+ /**
+ * Number of cells spanned horizontally by the item.
+ */
+ @ViewDebug.ExportedProperty
+ public int cellHSpan;
+
+ /**
+ * Number of cells spanned vertically by the item.
+ */
+ @ViewDebug.ExportedProperty
+ public int cellVSpan;
+
+ /**
+ * Is this item currently being dragged
+ */
+ public boolean isDragging;
+
+ // a data object that you can bind to this layout params
+ private Object mTag;
+
+ // X coordinate of the view in the layout.
+ @ViewDebug.ExportedProperty
+ int x;
+ // Y coordinate of the view in the layout.
+ @ViewDebug.ExportedProperty
+ int y;
+
+ public LayoutParams() {
+ super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ cellHSpan = 1;
+ cellVSpan = 1;
+ }
+
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ cellHSpan = 1;
+ cellVSpan = 1;
+ }
+
+ public LayoutParams(ViewGroup.LayoutParams source) {
+ super(source);
+ cellHSpan = 1;
+ cellVSpan = 1;
+ }
+
+ public LayoutParams(LayoutParams source) {
+ super(source);
+ this.cellX = source.cellX;
+ this.cellY = source.cellY;
+ this.cellHSpan = source.cellHSpan;
+ this.cellVSpan = source.cellVSpan;
+ }
+
+ public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
+ super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ this.cellX = cellX;
+ this.cellY = cellY;
+ this.cellHSpan = cellHSpan;
+ this.cellVSpan = cellVSpan;
+ }
+
+ public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
+ int hStartPadding, int vStartPadding) {
+
+ final int myCellHSpan = cellHSpan;
+ final int myCellVSpan = cellVSpan;
+ final int myCellX = cellX;
+ final int myCellY = cellY;
+
+ width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
+ leftMargin - rightMargin;
+ height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
+ topMargin - bottomMargin;
+
+ x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
+ y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+ }
+
+ public Object getTag() {
+ return mTag;
+ }
+
+ public void setTag(Object tag) {
+ mTag = tag;
+ }
+
+ public String toString() {
+ return "(" + this.cellX + ", " + this.cellY + ", " +
+ this.cellHSpan + ", " + this.cellVSpan + ")";
+ }
+ }
+}
diff --git a/src/com/android/launcher2/PagedViewExtendedLayout.java b/src/com/android/launcher2/PagedViewExtendedLayout.java
new file mode 100644
index 0000000..52df9f1
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewExtendedLayout.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.LinearLayout;
+
+/**
+ * The linear layout used strictly for the widget/wallpaper tab of the customization tray
+ */
+public class PagedViewExtendedLayout extends LinearLayout {
+ static final String TAG = "PagedViewWidgetLayout";
+
+ public PagedViewExtendedLayout(Context context) {
+ this(context, null);
+ }
+
+ public PagedViewExtendedLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PagedViewExtendedLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @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);
+ }
+ }
+}
diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
new file mode 100644
index 0000000..0af7b8a
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewIcon.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.widget.Checkable;
+
+import com.android.launcher.R;
+
+
+
+/**
+ * An icon on a PagedView, specifically for items in the launcher's paged view (with compound
+ * drawables on the top).
+ */
+public class PagedViewIcon extends CachedTextView implements Checkable {
+ private static final String TAG = "PagedViewIcon";
+
+ // holographic outline
+ private final Paint mPaint = new Paint();
+ private static HolographicOutlineHelper sHolographicOutlineHelper;
+ private Bitmap mCheckedOutline;
+ private Bitmap mHolographicOutline;
+ private Bitmap mIcon;
+
+ private PagedViewIconCache.Key mIconCacheKey;
+ private PagedViewIconCache mIconCache;
+
+ private int mAlpha = 255;
+ private int mHolographicAlpha;
+
+ private boolean mIsChecked;
+ private ObjectAnimator mCheckedAlphaAnimator;
+ private float mCheckedAlpha = 1.0f;
+ private int mCheckedFadeInDuration;
+ private int mCheckedFadeOutDuration;
+
+ // Highlight colors
+ private int mHoloBlurColor;
+ private int mHoloOutlineColor;
+
+ private static final HandlerThread sWorkerThread = new HandlerThread("pagedviewicon-helper");
+ static {
+ sWorkerThread.start();
+ }
+
+ private static final int MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE = 1;
+
+ private static final Handler sWorker = new Handler(sWorkerThread.getLooper()) {
+ private DeferredHandler mHandler = new DeferredHandler();
+ private Paint mPaint = new Paint();
+ public void handleMessage(Message msg) {
+ final PagedViewIcon icon = (PagedViewIcon) msg.obj;
+
+ final Bitmap holographicOutline = Bitmap.createBitmap(
+ icon.mIcon.getWidth(), icon.mIcon.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas holographicOutlineCanvas = new Canvas(holographicOutline);
+ holographicOutlineCanvas.drawBitmap(icon.mIcon, 0, 0, mPaint);
+
+ sHolographicOutlineHelper.applyThickExpensiveOutlineWithBlur(holographicOutline,
+ holographicOutlineCanvas, icon.mHoloBlurColor, icon.mHoloOutlineColor);
+
+ mHandler.post(new Runnable() {
+ public void run() {
+ icon.mHolographicOutline = holographicOutline;
+ icon.mIconCache.addOutline(icon.mIconCacheKey, holographicOutline);
+ icon.invalidate();
+ }
+ });
+ }
+ };
+
+ public PagedViewIcon(Context context) {
+ this(context, null);
+ }
+
+ public PagedViewIcon(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedViewIcon, defStyle, 0);
+ mHoloBlurColor = a.getColor(R.styleable.PagedViewIcon_blurColor, 0);
+ mHoloOutlineColor = a.getColor(R.styleable.PagedViewIcon_outlineColor, 0);
+ a.recycle();
+
+ if (sHolographicOutlineHelper == null) {
+ sHolographicOutlineHelper = new HolographicOutlineHelper();
+ }
+
+ // Set up fade in/out constants
+ final Resources r = context.getResources();
+ final int alpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha);
+ 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);
+ }
+
+ setFocusable(true);
+ setBackgroundDrawable(null);
+ }
+
+ private void queueHolographicOutlineCreation() {
+ // Generate the outline in the background
+ if (mHolographicOutline == null) {
+ Message m = sWorker.obtainMessage(MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE);
+ m.obj = this;
+ sWorker.sendMessage(m);
+ }
+ }
+
+ public void applyFromApplicationInfo(ApplicationInfo info, PagedViewIconCache cache,
+ boolean scaleUp, boolean createHolographicOutlines) {
+ mIcon = info.iconBitmap;
+ setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null);
+ setText(info.title);
+ setTag(info);
+
+ if (createHolographicOutlines) {
+ mIconCache = cache;
+ mIconCacheKey = new PagedViewIconCache.Key(info);
+ mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
+ queueHolographicOutlineCreation();
+ }
+ }
+
+ public void applyFromResolveInfo(ResolveInfo info, PackageManager packageManager,
+ PagedViewIconCache cache, IconCache modelIconCache, boolean createHolographicOutlines) {
+ mIcon = Utilities.createIconBitmap(
+ modelIconCache.getFullResIcon(info, packageManager), mContext);
+ setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null);
+ setText(info.loadLabel(packageManager));
+ setTag(info);
+
+ if (createHolographicOutlines) {
+ mIconCache = cache;
+ mIconCacheKey = new PagedViewIconCache.Key(info);
+ mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
+ queueHolographicOutlineCreation();
+ }
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ final float viewAlpha = sHolographicOutlineHelper.viewAlphaInterpolator(alpha);
+ final float holographicAlpha = sHolographicOutlineHelper.highlightAlphaInterpolator(alpha);
+ int newViewAlpha = (int) (viewAlpha * 255);
+ int newHolographicAlpha = (int) (holographicAlpha * 255);
+ if ((mAlpha != newViewAlpha) || (mHolographicAlpha != newHolographicAlpha)) {
+ mAlpha = newViewAlpha;
+ mHolographicAlpha = newHolographicAlpha;
+ super.setAlpha(viewAlpha);
+ }
+ }
+
+ public void invalidateCheckedImage() {
+ if (mCheckedOutline != null) {
+ mCheckedOutline.recycle();
+ mCheckedOutline = null;
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mAlpha > 0) {
+ super.onDraw(canvas);
+ }
+
+ Bitmap overlay = null;
+
+ // draw any blended overlays
+ if (mCheckedOutline == null) {
+ if (mHolographicOutline != null && mHolographicAlpha > 0) {
+ mPaint.setAlpha(mHolographicAlpha);
+ overlay = mHolographicOutline;
+ }
+ } else {
+ mPaint.setAlpha(255);
+ overlay = mCheckedOutline;
+ }
+
+ if (overlay != null) {
+ final int offset = getScrollX();
+ final int compoundPaddingLeft = getCompoundPaddingLeft();
+ final int compoundPaddingRight = getCompoundPaddingRight();
+ int hspace = getWidth() - compoundPaddingRight - compoundPaddingLeft;
+ canvas.drawBitmap(overlay,
+ offset + compoundPaddingLeft + (hspace - overlay.getWidth()) / 2,
+ mPaddingTop,
+ mPaint);
+ }
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ sWorker.removeMessages(MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE, this);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mIsChecked;
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ if (mIsChecked != checked) {
+ mIsChecked = checked;
+
+ float alpha;
+ int duration;
+ if (mIsChecked) {
+ alpha = mCheckedAlpha;
+ duration = mCheckedFadeInDuration;
+ } else {
+ alpha = 1.0f;
+ duration = mCheckedFadeOutDuration;
+ }
+
+ // Initialize the animator
+ if (mCheckedAlphaAnimator != null) {
+ mCheckedAlphaAnimator.cancel();
+ }
+ mCheckedAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), alpha);
+ mCheckedAlphaAnimator.setDuration(duration);
+ mCheckedAlphaAnimator.start();
+
+ invalidate();
+ }
+ }
+
+ @Override
+ public void toggle() {
+ setChecked(!mIsChecked);
+ }
+}
diff --git a/src/com/android/launcher2/PagedViewIconCache.java b/src/com/android/launcher2/PagedViewIconCache.java
new file mode 100644
index 0000000..de05ff1
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewIconCache.java
@@ -0,0 +1,133 @@
+/*
+ * 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.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.pm.ComponentInfo;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+
+/**
+ * Simple cache mechanism for PagedView outlines.
+ */
+public class PagedViewIconCache {
+ public static class Key {
+ public enum Type {
+ ApplicationInfoKey,
+ AppWidgetProviderInfoKey,
+ ResolveInfoKey
+ }
+ private final ComponentName mComponentName;
+ private final Type mType;
+
+ public Key(ApplicationInfo info) {
+ mComponentName = info.componentName;
+ mType = Type.ApplicationInfoKey;
+ }
+ public Key(ResolveInfo info) {
+ final ComponentInfo ci = info.activityInfo != null ? info.activityInfo :
+ info.serviceInfo;
+ mComponentName = new ComponentName(ci.packageName, ci.name);
+ mType = Type.AppWidgetProviderInfoKey;
+ }
+ public Key(AppWidgetProviderInfo info) {
+ mComponentName = info.provider;
+ mType = Type.ResolveInfoKey;
+ }
+
+ private ComponentName getComponentName() {
+ return mComponentName;
+ }
+ public boolean isKeyType(Type t) {
+ return (mType == t);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Key) {
+ Key k = (Key) o;
+ return mComponentName.equals(k.mComponentName);
+ }
+ return super.equals(o);
+ }
+ @Override
+ public int hashCode() {
+ return getComponentName().hashCode();
+ }
+ }
+
+ private final HashMap<Key, Bitmap> mIconOutlineCache = new HashMap<Key, Bitmap>();
+
+ public void clear() {
+ for (Key key : mIconOutlineCache.keySet()) {
+ mIconOutlineCache.get(key).recycle();
+ }
+ mIconOutlineCache.clear();
+ }
+ private void retainAll(HashSet<Key> keysToKeep, Key.Type t) {
+ HashSet<Key> keysToRemove = new HashSet<Key>(mIconOutlineCache.keySet());
+ keysToRemove.removeAll(keysToKeep);
+ for (Key key : keysToRemove) {
+ if (key.isKeyType(t)) {
+ mIconOutlineCache.get(key).recycle();
+ mIconOutlineCache.remove(key);
+ }
+ }
+ }
+ /** Removes all the keys to applications that aren't in the passed in collection */
+ public void retainAllApps(ArrayList<ApplicationInfo> keys) {
+ HashSet<Key> keysSet = new HashSet<Key>();
+ for (ApplicationInfo info : keys) {
+ keysSet.add(new Key(info));
+ }
+ retainAll(keysSet, Key.Type.ApplicationInfoKey);
+ }
+ /** Removes all the keys to shortcuts that aren't in the passed in collection */
+ public void retainAllShortcuts(List<ResolveInfo> keys) {
+ HashSet<Key> keysSet = new HashSet<Key>();
+ for (ResolveInfo info : keys) {
+ keysSet.add(new Key(info));
+ }
+ retainAll(keysSet, Key.Type.ResolveInfoKey);
+ }
+ /** Removes all the keys to widgets that aren't in the passed in collection */
+ public void retainAllAppWidgets(List<AppWidgetProviderInfo> keys) {
+ HashSet<Key> keysSet = new HashSet<Key>();
+ for (AppWidgetProviderInfo info : keys) {
+ keysSet.add(new Key(info));
+ }
+ retainAll(keysSet, Key.Type.AppWidgetProviderInfoKey);
+ }
+ public void addOutline(Key key, Bitmap b) {
+ mIconOutlineCache.put(key, b);
+ }
+ public void removeOutline(Key key) {
+ if (mIconOutlineCache.containsKey(key)) {
+ mIconOutlineCache.get(key).recycle();
+ mIconOutlineCache.remove(key);
+ }
+ }
+ public Bitmap getOutline(Key key) {
+ return mIconOutlineCache.get(key);
+ }
+}
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
new file mode 100644
index 0000000..9b83f48
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewWidget.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.animation.ObjectAnimator;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Checkable;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.launcher.R;
+
+/**
+ * The linear layout used strictly for the widget/wallpaper tab of the customization tray
+ */
+public class PagedViewWidget extends LinearLayout implements Checkable {
+ static final String TAG = "PagedViewWidgetLayout";
+
+ private final Paint mPaint = new Paint();
+ private static HolographicOutlineHelper sHolographicOutlineHelper;
+ private Bitmap mHolographicOutline;
+ private final Canvas mHolographicOutlineCanvas = new Canvas();
+ private FastBitmapDrawable mPreview;
+
+ private PagedViewIconCache.Key mIconCacheKey;
+ private PagedViewIconCache mIconCache;
+
+ private int mAlpha = 255;
+ private int mHolographicAlpha;
+
+ // Highlight colors
+ private int mHoloBlurColor;
+ private int mHoloOutlineColor;
+
+ private boolean mIsChecked;
+ private ObjectAnimator mCheckedAlphaAnimator;
+ private float mCheckedAlpha = 1.0f;
+ private int mCheckedFadeInDuration;
+ private int mCheckedFadeOutDuration;
+
+ private static final HandlerThread sWorkerThread = new HandlerThread("pagedviewwidget-helper");
+ static {
+ sWorkerThread.start();
+ }
+
+ private static final int MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE = 1;
+
+ private static final Handler sWorker = new Handler(sWorkerThread.getLooper()) {
+ private DeferredHandler mHandler = new DeferredHandler();
+ public void handleMessage(Message msg) {
+ final PagedViewWidget widget = (PagedViewWidget) msg.obj;
+ final int prevAlpha = widget.mPreview.getAlpha();
+ final Bitmap outline = Bitmap.createBitmap(widget.getWidth(), widget.getHeight(),
+ Bitmap.Config.ARGB_8888);
+
+ widget.mHolographicOutlineCanvas.setBitmap(outline);
+ widget.mHolographicOutlineCanvas.save();
+ widget.mHolographicOutlineCanvas.translate(widget.mPaddingLeft, widget.mPaddingTop);
+ widget.mPreview.setAlpha(255);
+ widget.mPreview.draw(widget.mHolographicOutlineCanvas);
+ widget.mPreview.setAlpha(prevAlpha);
+ // Temporary workaround to make the default widget outlines visible
+ widget.mHolographicOutlineCanvas.drawColor(Color.argb(156, 0, 0, 0), Mode.SRC_OVER);
+ widget.mHolographicOutlineCanvas.restore();
+
+ sHolographicOutlineHelper.applyThickExpensiveOutlineWithBlur(outline,
+ widget.mHolographicOutlineCanvas, widget.mHoloBlurColor,
+ widget.mHoloOutlineColor);
+
+ mHandler.post(new Runnable() {
+ public void run() {
+ widget.mHolographicOutline = outline;
+ widget.mIconCache.addOutline(widget.mIconCacheKey, outline);
+ widget.invalidate();
+ }
+ });
+ }
+ };
+
+ public PagedViewWidget(Context context) {
+ this(context, null);
+ }
+
+ public PagedViewWidget(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PagedViewWidget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedViewWidget,
+ defStyle, 0);
+ mHoloBlurColor = a.getColor(R.styleable.PagedViewWidget_blurColor, 0);
+ mHoloOutlineColor = a.getColor(R.styleable.PagedViewWidget_outlineColor, 0);
+ a.recycle();
+
+ if (sHolographicOutlineHelper == null) {
+ sHolographicOutlineHelper = new HolographicOutlineHelper();
+ }
+
+ // Set up fade in/out constants
+ final Resources r = context.getResources();
+ final int alpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha);
+ 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);
+ }
+
+ setFocusable(true);
+ setWillNotDraw(false);
+ setClipToPadding(false);
+ }
+
+ private void queueHolographicOutlineCreation() {
+ // Generate the outline in the background
+ if (mHolographicOutline == null && mPreview != null) {
+ Message m = sWorker.obtainMessage(MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE);
+ m.obj = this;
+ sWorker.sendMessage(m);
+ }
+ }
+
+ public void applyFromAppWidgetProviderInfo(AppWidgetProviderInfo info,
+ FastBitmapDrawable preview, int maxWidth, int[] cellSpan,
+ PagedViewIconCache cache, boolean createHolographicOutline) {
+ final ImageView image = (ImageView) findViewById(R.id.widget_preview);
+ image.setMaxWidth(maxWidth);
+ image.setImageDrawable(preview);
+ 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.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) {
+ ImageView image = (ImageView) findViewById(R.id.wallpaper_preview);
+ image.setMaxWidth(maxWidth);
+ image.setImageDrawable(preview);
+ TextView name = (TextView) findViewById(R.id.wallpaper_name);
+ name.setText(info.loadLabel(packageManager));
+ name.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+ if (createHolographicOutline) {
+ mIconCache = cache;
+ mIconCacheKey = new PagedViewIconCache.Key(info);
+ mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
+ mPreview = preview;
+ }
+ }
+
+ @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 void onDraw(Canvas canvas) {
+ if (mAlpha > 0) {
+ super.onDraw(canvas);
+ }
+
+ // draw any blended overlays
+ if (mHolographicOutline != null && mHolographicAlpha > 0) {
+ mPaint.setAlpha(mHolographicAlpha);
+ canvas.drawBitmap(mHolographicOutline, 0, 0, mPaint);
+ }
+ }
+
+ @Override
+ protected boolean onSetAlpha(int alpha) {
+ return true;
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ final float viewAlpha = sHolographicOutlineHelper.viewAlphaInterpolator(alpha);
+ final float holographicAlpha = sHolographicOutlineHelper.highlightAlphaInterpolator(alpha);
+ int newViewAlpha = (int) (viewAlpha * 255);
+ int newHolographicAlpha = (int) (holographicAlpha * 255);
+ if ((mAlpha != newViewAlpha) || (mHolographicAlpha != newHolographicAlpha)) {
+ mAlpha = newViewAlpha;
+ mHolographicAlpha = newHolographicAlpha;
+ setChildrenAlpha(viewAlpha);
+ super.setAlpha(viewAlpha);
+ }
+ }
+
+ private void setChildrenAlpha(float alpha) {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ getChildAt(i).setAlpha(alpha);
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ if (w > 0 && h > 0) {
+ queueHolographicOutlineCreation();
+ }
+
+ super.onSizeChanged(w, h, oldw, oldh);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ sWorker.removeMessages(MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE, this);
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ if (mIsChecked != checked) {
+ mIsChecked = checked;
+
+ float alpha;
+ int duration;
+ if (mIsChecked) {
+ alpha = mCheckedAlpha;
+ duration = mCheckedFadeInDuration;
+ } else {
+ alpha = 1.0f;
+ duration = mCheckedFadeOutDuration;
+ }
+
+ // Initialize the animator
+ if (mCheckedAlphaAnimator != null) {
+ mCheckedAlphaAnimator.cancel();
+ }
+ mCheckedAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), alpha);
+ mCheckedAlphaAnimator.setDuration(duration);
+ mCheckedAlphaAnimator.start();
+
+ invalidate();
+ }
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mIsChecked;
+ }
+
+ @Override
+ public void toggle() {
+ setChecked(!mIsChecked);
+ }
+}
diff --git a/src/com/android/launcher2/PagedViewWithDraggableItems.java b/src/com/android/launcher2/PagedViewWithDraggableItems.java
new file mode 100644
index 0000000..5fa7be7
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewWithDraggableItems.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+
+/* Class that does most of the work of enabling dragging items out of a PagedView by performing a
+ * vertical drag. Used by both CustomizePagedView and AllAppsPagedView.
+ * Subclasses must do the following:
+ * * call setDragSlopeThreshold after making an instance of the PagedViewWithDraggableItems
+ * * call child.setOnLongClickListener(this) and child.setOnTouchListener(this) on all children
+ * (good place to do it is in syncPageItems)
+ * * override beginDragging(View) (but be careful to call super.beginDragging(View)
+ *
+ */
+public abstract class PagedViewWithDraggableItems extends PagedView
+ implements View.OnLongClickListener, View.OnTouchListener {
+ private View mLastTouchedItem;
+ private boolean mIsDragging;
+ private boolean mIsDragEnabled;
+ private float mDragSlopeThreshold;
+
+ public PagedViewWithDraggableItems(Context context) {
+ super(context, null);
+ }
+
+ public PagedViewWithDraggableItems(Context context, AttributeSet attrs) {
+ super(context, attrs, 0);
+ }
+
+ public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ protected boolean beginDragging(View v) {
+ boolean wasDragging = mIsDragging;
+ mIsDragging = true;
+ return !wasDragging;
+ }
+
+ protected void cancelDragging() {
+ mIsDragging = false;
+ mLastTouchedItem = null;
+ mIsDragEnabled = false;
+ }
+
+ private void handleTouchEvent(MotionEvent ev) {
+ final int action = ev.getAction();
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ cancelDragging();
+ mIsDragEnabled = true;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging && mIsDragEnabled) {
+ determineDraggingStart(ev);
+ }
+ break;
+ }
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ handleTouchEvent(ev);
+ return super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ handleTouchEvent(ev);
+ return super.onTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ mLastTouchedItem = v;
+ mIsDragEnabled = true;
+ return false;
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ // Return early if this is not initiated from a touch
+ if (!v.isInTouchMode()) return false;
+ // Return early if we are still animating the pages
+ if (mNextPage != INVALID_PAGE) return false;
+ return beginDragging(v);
+ }
+
+
+ /*
+ * Determines if we should change the touch state to start scrolling after the
+ * user moves their touch point too far.
+ */
+ protected void determineScrollingStart(MotionEvent ev) {
+ if (!mIsDragging) super.determineScrollingStart(ev);
+ }
+
+ /*
+ * Determines if we should change the touch state to start dragging after the
+ * user moves their touch point far enough.
+ */
+ protected void determineDraggingStart(MotionEvent ev) {
+ /*
+ * Locally do absolute value. mLastMotionX is set to the y value
+ * of the down event.
+ */
+ final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ final float x = ev.getX(pointerIndex);
+ final float y = ev.getY(pointerIndex);
+ final int xDiff = (int) Math.abs(x - mLastMotionX);
+ final int yDiff = (int) Math.abs(y - mLastMotionY);
+
+ final int touchSlop = mTouchSlop;
+ boolean yMoved = yDiff > touchSlop;
+ boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold;
+
+ if (isUpwardMotion && yMoved && mLastTouchedItem != null) {
+ // Drag if the user moved far enough along the Y axis
+ beginDragging(mLastTouchedItem);
+
+ // Cancel any pending long press
+ if (mAllowLongPress) {
+ mAllowLongPress = false;
+ // Try canceling the long press. It could also have been scheduled
+ // by a distant descendant, so use the mAllowLongPress flag to block
+ // everything
+ final View currentPage = getPageAt(mCurrentPage);
+ if (currentPage != null) {
+ currentPage.cancelLongPress();
+ }
+ }
+ }
+ }
+
+ public void setDragSlopeThreshold(float dragSlopeThreshold) {
+ mDragSlopeThreshold = dragSlopeThreshold;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ cancelDragging();
+ super.onDetachedFromWindow();
+ }
+}
diff --git a/src/com/android/launcher2/PendingAddItemInfo.java b/src/com/android/launcher2/PendingAddItemInfo.java
new file mode 100644
index 0000000..7b564e0
--- /dev/null
+++ b/src/com/android/launcher2/PendingAddItemInfo.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.os.Parcelable;
+
+/**
+ * We pass this object with a drag from the customization tray
+ */
+class PendingAddItemInfo extends ItemInfo {
+ /**
+ * The component that will be created.
+ */
+ ComponentName componentName;
+}
+
+class PendingAddWidgetInfo extends PendingAddItemInfo {
+ int minWidth;
+ int minHeight;
+
+ // Any configuration data that we want to pass to a configuration activity when
+ // starting up a widget
+ String mimeType;
+ Parcelable configurationData;
+
+ public PendingAddWidgetInfo(AppWidgetProviderInfo i, String dataMimeType, Parcelable data) {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+ componentName = i.provider;
+ minWidth = i.minWidth;
+ minHeight = i.minHeight;
+ if (dataMimeType != null && data != null) {
+ mimeType = dataMimeType;
+ configurationData = data;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java
index 2c5aec4..72f2d51 100644
--- a/src/com/android/launcher2/ShortcutInfo.java
+++ b/src/com/android/launcher2/ShortcutInfo.java
@@ -16,16 +16,14 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
import android.content.ComponentName;
import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
import android.util.Log;
-import java.util.ArrayList;
-
/**
* Represents a launchable icon on the workspaces and in folders.
*/
diff --git a/src/com/android/launcher2/ShortcutsAdapter.java b/src/com/android/launcher2/ShortcutsAdapter.java
index 19c3af0..93c500a 100644
--- a/src/com/android/launcher2/ShortcutsAdapter.java
+++ b/src/com/android/launcher2/ShortcutsAdapter.java
@@ -16,16 +16,15 @@
package com.android.launcher2;
+import java.util.ArrayList;
+
import android.content.Context;
-import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
-import java.util.ArrayList;
-
import com.android.launcher.R;
/**
diff --git a/src/com/android/launcher2/SmoothPagedView.java b/src/com/android/launcher2/SmoothPagedView.java
new file mode 100644
index 0000000..8b0a835
--- /dev/null
+++ b/src/com/android/launcher2/SmoothPagedView.java
@@ -0,0 +1,188 @@
+/*
+ * 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.util.AttributeSet;
+import android.view.animation.Interpolator;
+import android.widget.Scroller;
+
+public abstract class SmoothPagedView extends PagedView {
+ private static final float SMOOTHING_SPEED = 0.75f;
+ private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
+
+ private float mBaseLineFlingVelocity;
+ private float mFlingVelocityInfluence;
+
+ static final int DEFAULT_MODE = 0;
+ static final int X_LARGE_MODE = 1;
+
+ int mScrollMode;
+
+ private Interpolator mScrollInterpolator;
+
+ private static class WorkspaceOvershootInterpolator implements Interpolator {
+ private static final float DEFAULT_TENSION = 1.3f;
+ private float mTension;
+
+ public WorkspaceOvershootInterpolator() {
+ mTension = DEFAULT_TENSION;
+ }
+
+ public void setDistance(int distance) {
+ mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
+ }
+
+ public void disableSettle() {
+ mTension = 0.f;
+ }
+
+ public float getInterpolation(float t) {
+ // _o(t) = t * t * ((tension + 1) * t + tension)
+ // o(t) = _o(t - 1) + 1
+ t -= 1.0f;
+ return t * t * ((mTension + 1) * t + mTension) + 1.0f;
+ }
+ }
+
+ /**
+ * Used to inflate the Workspace from XML.
+ *
+ * @param context The application's context.
+ * @param attrs The attributes set containing the Workspace's customization values.
+ */
+ public SmoothPagedView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ /**
+ * Used to inflate the Workspace from XML.
+ *
+ * @param context The application's context.
+ * @param attrs The attributes set containing the Workspace's customization values.
+ * @param defStyle Unused.
+ */
+ public SmoothPagedView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ mUsePagingTouchSlop = false;
+
+ // This means that we'll take care of updating the scroll parameter ourselves (we do it
+ // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones
+ mDeferScrollUpdate = mScrollMode != X_LARGE_MODE;
+ }
+
+ protected int getScrollMode() {
+ return DEFAULT_MODE;
+ }
+
+ /**
+ * Initializes various states for this workspace.
+ */
+ @Override
+ protected void init() {
+ super.init();
+
+ mScrollMode = getScrollMode();
+ if (mScrollMode == DEFAULT_MODE) {
+ mBaseLineFlingVelocity = 2500.0f;
+ mFlingVelocityInfluence = 0.4f;
+ mScrollInterpolator = new WorkspaceOvershootInterpolator();
+ mScroller = new Scroller(getContext(), mScrollInterpolator);
+ }
+ }
+
+ @Override
+ protected void snapToDestination() {
+ if (mScrollMode == X_LARGE_MODE) {
+ super.snapToDestination();
+ } else {
+ snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0);
+ }
+ }
+
+ @Override
+ protected void snapToPageWithVelocity(int whichPage, int velocity) {
+ if (mScrollMode == X_LARGE_MODE) {
+ super.snapToPageWithVelocity(whichPage, velocity);
+ } else {
+ snapToPageWithVelocity(whichPage, 0, true);
+ }
+ }
+
+ private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) {
+ // if (!mScroller.isFinished()) return;
+
+ whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
+
+ final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage));
+ final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
+ final int delta = newX - mUnboundedScrollX;
+ int duration = (screenDelta + 1) * 100;
+
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
+
+ if (settle) {
+ ((WorkspaceOvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
+ } else {
+ ((WorkspaceOvershootInterpolator) mScrollInterpolator).disableSettle();
+ }
+
+ velocity = Math.abs(velocity);
+ if (velocity > 0) {
+ duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence;
+ } else {
+ duration += 100;
+ }
+
+ snapToPage(whichPage, delta, duration);
+ }
+
+ @Override
+ protected void snapToPage(int whichPage) {
+ if (mScrollMode == X_LARGE_MODE) {
+ super.snapToPage(whichPage);
+ } else {
+ snapToPageWithVelocity(whichPage, 0, false);
+ }
+ }
+
+ @Override
+ public void computeScroll() {
+ if (mScrollMode == X_LARGE_MODE) {
+ super.computeScroll();
+ } else {
+ boolean scrollComputed = computeScrollHelper();
+
+ if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) {
+ final float now = System.nanoTime() / NANOTIME_DIV;
+ final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
+
+ final float dx = mTouchX - mUnboundedScrollX;
+ scrollTo(Math.round(mUnboundedScrollX + dx * e), mScrollY);
+ mSmoothingTime = now;
+
+ // Keep generating points as long as we're more than 1px away from the target
+ if (dx > 1.f || dx < -1.f) {
+ invalidate();
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher2/SpringLoadedDragController.java b/src/com/android/launcher2/SpringLoadedDragController.java
new file mode 100644
index 0000000..a734258
--- /dev/null
+++ b/src/com/android/launcher2/SpringLoadedDragController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+public class SpringLoadedDragController implements OnAlarmListener {
+ // how long the user must hover over a mini-screen before it unshrinks
+ final long ENTER_SPRING_LOAD_HOVER_TIME = 1000;
+ final long EXIT_SPRING_LOAD_HOVER_TIME = 200;
+
+ Alarm mAlarm;
+
+ // the screen the user is currently hovering over, if any
+ private CellLayout mScreen;
+ private Launcher mLauncher;
+
+ public SpringLoadedDragController(Launcher launcher) {
+ mLauncher = launcher;
+ mAlarm = new Alarm();
+ mAlarm.setOnAlarmListener(this);
+ }
+
+ public void onDragEnter(CellLayout cl) {
+ mScreen = cl;
+ mAlarm.setAlarm(ENTER_SPRING_LOAD_HOVER_TIME);
+ }
+
+ public void onDragExit() {
+ if (mScreen != null) {
+ mScreen.onDragExit();
+ }
+ mScreen = null;
+ mAlarm.setAlarm(EXIT_SPRING_LOAD_HOVER_TIME);
+ }
+
+ // this is called when our timer runs out
+ public void onAlarm(Alarm alarm) {
+ if (mScreen != null) {
+ // we're currently hovering over a screen
+ mLauncher.enterSpringLoadedDragMode(mScreen);
+ } else {
+ mLauncher.exitSpringLoadedDragMode();
+ }
+ }
+}
diff --git a/src/com/android/launcher2/SymmetricalLinearTween.java b/src/com/android/launcher2/SymmetricalLinearTween.java
index 2e0ed8f..da02242 100644
--- a/src/com/android/launcher2/SymmetricalLinearTween.java
+++ b/src/com/android/launcher2/SymmetricalLinearTween.java
@@ -17,9 +17,7 @@
package com.android.launcher2;
import android.os.Handler;
-import android.os.Message;
import android.os.SystemClock;
-import android.util.Log;
/**
* Provides an animation between 0.0f and 1.0f over a given duration.
diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java
index d49c27a..b362fbd 100644
--- a/src/com/android/launcher2/UserFolder.java
+++ b/src/com/android/launcher2/UserFolder.java
@@ -1,12 +1,9 @@
package com.android.launcher2;
import android.content.Context;
-import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.ArrayAdapter;
import com.android.launcher.R;
@@ -40,11 +37,6 @@
itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT)
&& item.container != mInfo.id;
}
-
- public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo, Rect recycle) {
- return null;
- }
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
@@ -79,6 +71,10 @@
}
}
+ public boolean isDropEnabled() {
+ return true;
+ }
+
void bind(FolderInfo info) {
super.bind(info);
setContentAdapter(new ShortcutsAdapter(mContext, ((UserFolderInfo) info).contents));
@@ -91,4 +87,10 @@
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/Utilities.java b/src/com/android/launcher2/Utilities.java
index 757e48e..60f71f5 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -16,9 +16,8 @@
package com.android.launcher2;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.PaintDrawable;
+import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
@@ -26,19 +25,19 @@
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.TableMaskFilter;
import android.graphics.Typeface;
-import android.text.Layout.Alignment;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
import android.text.StaticLayout;
import android.text.TextPaint;
+import android.text.Layout.Alignment;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.content.res.Resources;
-import android.content.Context;
import com.android.launcher.R;
@@ -55,12 +54,10 @@
private static int sIconTextureWidth = -1;
private static int sIconTextureHeight = -1;
- private static final Paint sPaint = new Paint();
private static final Paint sBlurPaint = new Paint();
private static final Paint sGlowColorPressedPaint = new Paint();
private static final Paint sGlowColorFocusedPaint = new Paint();
private static final Paint sDisabledPaint = new Paint();
- private static final Rect sBounds = new Rect();
private static final Rect sOldBounds = new Rect();
private static final Canvas sCanvas = new Canvas();
@@ -238,7 +235,7 @@
final DisplayMetrics metrics = resources.getDisplayMetrics();
final float density = metrics.density;
- sIconWidth = sIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
+ sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
sIconTextureWidth = sIconTextureHeight = sIconWidth + 2;
sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
diff --git a/src/com/android/launcher2/WallpaperChooser.java b/src/com/android/launcher2/WallpaperChooser.java
index bf8ba2e..2311d1e 100644
--- a/src/com/android/launcher2/WallpaperChooser.java
+++ b/src/com/android/launcher2/WallpaperChooser.java
@@ -16,236 +16,29 @@
package com.android.launcher2;
-import android.app.Activity;
-import android.app.WallpaperManager;
-import android.content.res.Resources;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.AsyncTask;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.Gallery;
-import android.widget.ImageView;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
import com.android.launcher.R;
-public class WallpaperChooser extends Activity implements AdapterView.OnItemSelectedListener,
- OnClickListener {
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.os.Bundle;
+
+public class WallpaperChooser extends Activity {
private static final String TAG = "Launcher.WallpaperChooser";
- private Gallery mGallery;
- private ImageView mImageView;
- private boolean mIsWallpaperSet;
-
- private Bitmap mBitmap;
-
- private ArrayList<Integer> mThumbs;
- private ArrayList<Integer> mImages;
- private WallpaperLoader mLoader;
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.wallpaper_chooser_base);
- findWallpapers();
-
- setContentView(R.layout.wallpaper_chooser);
-
- mGallery = (Gallery) findViewById(R.id.gallery);
- mGallery.setAdapter(new ImageAdapter(this));
- mGallery.setOnItemSelectedListener(this);
- mGallery.setCallbackDuringFling(false);
-
- findViewById(R.id.set).setOnClickListener(this);
-
- mImageView = (ImageView) findViewById(R.id.wallpaper);
- }
-
- private void findWallpapers() {
- mThumbs = new ArrayList<Integer>(24);
- mImages = new ArrayList<Integer>(24);
-
- final Resources resources = getResources();
- // Context.getPackageName() may return the "original" package name,
- // com.android.launcher2; Resources needs the real package name,
- // com.android.launcher. So we ask Resources for what it thinks the
- // package name should be.
- final String packageName = resources.getResourcePackageName(R.array.wallpapers);
-
- addWallpapers(resources, packageName, R.array.wallpapers);
- addWallpapers(resources, packageName, R.array.extra_wallpapers);
- }
-
- private void addWallpapers(Resources resources, String packageName, int list) {
- final String[] extras = resources.getStringArray(list);
- for (String extra : extras) {
- int res = resources.getIdentifier(extra, "drawable", packageName);
- if (res != 0) {
- final int thumbRes = resources.getIdentifier(extra + "_small",
- "drawable", packageName);
-
- if (thumbRes != 0) {
- mThumbs.add(thumbRes);
- mImages.add(res);
- // Log.d(TAG, "addWallpapers: [" + packageName + "]: " + extra + " (" + res + ")");
- }
- }
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mIsWallpaperSet = false;
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
- mLoader.cancel(true);
- mLoader = null;
- }
- }
-
- public void onItemSelected(AdapterView parent, View v, int position, long id) {
- if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
- mLoader.cancel();
- }
- mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
- }
-
- /*
- * When using touch if you tap an image it triggers both the onItemClick and
- * the onTouchEvent causing the wallpaper to be set twice. Ensure we only
- * set the wallpaper once.
- */
- private void selectWallpaper(int position) {
- if (mIsWallpaperSet) {
- return;
- }
-
- mIsWallpaperSet = true;
- try {
- WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE);
- wpm.setResource(mImages.get(position));
- setResult(RESULT_OK);
- finish();
- } catch (IOException e) {
- Log.e(TAG, "Failed to set wallpaper: " + e);
- }
- }
-
- public void onNothingSelected(AdapterView parent) {
- }
-
- private class ImageAdapter extends BaseAdapter {
- private LayoutInflater mLayoutInflater;
-
- ImageAdapter(WallpaperChooser context) {
- mLayoutInflater = context.getLayoutInflater();
- }
-
- public int getCount() {
- return mThumbs.size();
- }
-
- public Object getItem(int position) {
- return position;
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- ImageView image;
-
- if (convertView == null) {
- image = (ImageView) mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
- } else {
- image = (ImageView) convertView;
- }
-
- int thumbRes = mThumbs.get(position);
- image.setImageResource(thumbRes);
- Drawable thumbDrawable = image.getDrawable();
- if (thumbDrawable != null) {
- thumbDrawable.setDither(true);
- } else {
- Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
- + position);
- }
- return image;
- }
- }
-
- public void onClick(View v) {
- selectWallpaper(mGallery.getSelectedItemPosition());
- }
-
- class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
- BitmapFactory.Options mOptions;
-
- WallpaperLoader() {
- mOptions = new BitmapFactory.Options();
- mOptions.inDither = false;
- mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
- }
-
- protected Bitmap doInBackground(Integer... params) {
- if (isCancelled()) return null;
- try {
- return BitmapFactory.decodeResource(getResources(),
- mImages.get(params[0]), mOptions);
- } catch (OutOfMemoryError e) {
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(Bitmap b) {
- if (b == null) return;
-
- if (!isCancelled() && !mOptions.mCancel) {
- // Help the GC
- if (mBitmap != null) {
- mBitmap.recycle();
- }
-
- final ImageView view = mImageView;
- view.setImageBitmap(b);
-
- mBitmap = b;
-
- final Drawable drawable = view.getDrawable();
- drawable.setFilterBitmap(true);
- drawable.setDither(true);
-
- view.postInvalidate();
-
- mLoader = null;
- } else {
- b.recycle();
- }
- }
-
- void cancel() {
- mOptions.requestCancelDecode();
- super.cancel(true);
+ Fragment fragmentView =
+ getFragmentManager().findFragmentById(R.id.wallpaper_chooser_fragment);
+ if (fragmentView == null) {
+ /* When the screen is XLarge, the fragment is not included in the layout, so show it
+ * as a dialog
+ */
+ DialogFragment fragment = WallpaperChooserDialogFragment.newInstance();
+ fragment.show(getFragmentManager(), "dialog");
}
}
}
diff --git a/src/com/android/launcher2/WallpaperChooserDialogFragment.java b/src/com/android/launcher2/WallpaperChooserDialogFragment.java
new file mode 100644
index 0000000..ec0f8a2
--- /dev/null
+++ b/src/com/android/launcher2/WallpaperChooserDialogFragment.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher2;
+
+import com.android.launcher.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.Gallery;
+import android.widget.GridView;
+import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.SpinnerAdapter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class WallpaperChooserDialogFragment extends DialogFragment implements
+ AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
+
+ private static final String TAG = "Launcher.WallpaperChooserDialogFragment";
+ private static final String EMBEDDED_KEY = "com.android.launcher2."
+ + "WallpaperChooserDialogFragment.EMBEDDED_KEY";
+
+ private boolean mEmbedded;
+ private ImageView mImageView = null;
+ private Bitmap mBitmap = null;
+
+ private ArrayList<Integer> mThumbs;
+ private ArrayList<Integer> mImages;
+ private WallpaperLoader mLoader;
+
+ public static WallpaperChooserDialogFragment newInstance() {
+ WallpaperChooserDialogFragment fragment = new WallpaperChooserDialogFragment();
+ fragment.setCancelable(true);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (savedInstanceState != null && savedInstanceState.containsKey(EMBEDDED_KEY)) {
+ mEmbedded = savedInstanceState.getBoolean(EMBEDDED_KEY);
+ } else {
+ mEmbedded = isInLayout();
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putBoolean(EMBEDDED_KEY, mEmbedded);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
+ mLoader.cancel(true);
+ mLoader = null;
+ }
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ /* On orientation changes, the dialog is effectively "dismissed" so this is called
+ * when the activity is no longer associated with this dying dialog fragment. We
+ * should just safely ignore this case by checking if getActivity() returns null
+ */
+ Activity activity = getActivity();
+ if (activity != null) {
+ activity.finish();
+ }
+ }
+
+ /* This will only be called when in XLarge mode, since this Fragment is invoked like
+ * a dialog in that mode
+ */
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final View v = getActivity().getLayoutInflater().inflate(
+ R.layout.wallpaper_chooser, null, false);
+
+ GridView gridView = (GridView) v.findViewById(R.id.gallery);
+ gridView.setOnItemClickListener(this);
+ gridView.setAdapter(new ImageAdapter(getActivity()));
+
+ final int viewInset =
+ getResources().getDimensionPixelSize(R.dimen.alert_dialog_content_inset);
+
+ FrameLayout wallPaperList = (FrameLayout) v.findViewById(R.id.wallpaper_list);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setNegativeButton(R.string.wallpaper_cancel, null);
+ builder.setTitle(R.string.wallpaper_dialog_title);
+ builder.setView(wallPaperList, viewInset, viewInset, viewInset, viewInset);
+ return builder.create();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ findWallpapers();
+
+ /* If this fragment is embedded in the layout of this activity, then we should
+ * generate a view to display. Otherwise, a dialog will be created in
+ * onCreateDialog()
+ */
+ if (mEmbedded) {
+ View view = inflater.inflate(R.layout.wallpaper_chooser, container, false);
+
+ final Gallery gallery = (Gallery) view.findViewById(R.id.gallery);
+ gallery.setCallbackDuringFling(false);
+ gallery.setOnItemSelectedListener(this);
+ gallery.setAdapter(new ImageAdapter(getActivity()));
+
+ View setButton = view.findViewById(R.id.set);
+ setButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ selectWallpaper(gallery.getSelectedItemPosition());
+ }
+ });
+ mImageView = (ImageView) view.findViewById(R.id.wallpaper);
+ return view;
+ }
+ return null;
+ }
+
+ private void selectWallpaper(int position) {
+ try {
+ WallpaperManager wpm = (WallpaperManager) getActivity().getSystemService(
+ Context.WALLPAPER_SERVICE);
+ wpm.setResource(mImages.get(position));
+ Activity activity = getActivity();
+ activity.setResult(Activity.RESULT_OK);
+ activity.finish();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to set wallpaper: " + e);
+ }
+ }
+
+ // Click handler for the Dialog's GridView
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ selectWallpaper(position);
+ }
+
+ // Selection handler for the embedded Gallery view
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
+ mLoader.cancel();
+ }
+ mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+
+ private void findWallpapers() {
+ mThumbs = new ArrayList<Integer>(24);
+ mImages = new ArrayList<Integer>(24);
+
+ final Resources resources = getResources();
+ // Context.getPackageName() may return the "original" package name,
+ // com.android.launcher2; Resources needs the real package name,
+ // com.android.launcher. So we ask Resources for what it thinks the
+ // package name should be.
+ final String packageName = resources.getResourcePackageName(R.array.wallpapers);
+
+ addWallpapers(resources, packageName, R.array.wallpapers);
+ addWallpapers(resources, packageName, R.array.extra_wallpapers);
+ }
+
+ private void addWallpapers(Resources resources, String packageName, int list) {
+ final String[] extras = resources.getStringArray(list);
+ for (String extra : extras) {
+ int res = resources.getIdentifier(extra, "drawable", packageName);
+ if (res != 0) {
+ final int thumbRes = resources.getIdentifier(extra + "_small",
+ "drawable", packageName);
+
+ if (thumbRes != 0) {
+ mThumbs.add(thumbRes);
+ mImages.add(res);
+ // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
+ }
+ }
+ }
+ }
+
+ private class ImageAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
+ private LayoutInflater mLayoutInflater;
+
+ ImageAdapter(Activity activity) {
+ mLayoutInflater = activity.getLayoutInflater();
+ }
+
+ public int getCount() {
+ return mThumbs.size();
+ }
+
+ public Object getItem(int position) {
+ return position;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view;
+
+ if (convertView == null) {
+ view = mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
+ } else {
+ view = convertView;
+ }
+
+ ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
+
+ int thumbRes = mThumbs.get(position);
+ image.setImageResource(thumbRes);
+ Drawable thumbDrawable = image.getDrawable();
+ if (thumbDrawable != null) {
+ thumbDrawable.setDither(true);
+ } else {
+ Log.e(TAG, "Error decoding thumbnail resId=" + thumbRes + " for wallpaper #"
+ + position);
+ }
+
+ return view;
+ }
+ }
+
+ class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
+ BitmapFactory.Options mOptions;
+
+ WallpaperLoader() {
+ mOptions = new BitmapFactory.Options();
+ mOptions.inDither = false;
+ mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ }
+
+ @Override
+ protected Bitmap doInBackground(Integer... params) {
+ if (isCancelled()) return null;
+ try {
+ return BitmapFactory.decodeResource(getResources(),
+ mImages.get(params[0]), mOptions);
+ } catch (OutOfMemoryError e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap b) {
+ if (b == null) return;
+
+ if (!isCancelled() && !mOptions.mCancel) {
+ // Help the GC
+ if (mBitmap != null) {
+ mBitmap.recycle();
+ }
+
+ // This should always be the case, but check anyways
+ final ImageView view = mImageView;
+ if (view != null) {
+ view.setImageBitmap(b);
+
+ mBitmap = b;
+
+ final Drawable drawable = view.getDrawable();
+ drawable.setFilterBitmap(true);
+ drawable.setDither(true);
+
+ view.postInvalidate();
+ }
+
+ mLoader = null;
+ } else {
+ b.recycle();
+ }
+ }
+
+ void cancel() {
+ mOptions.requestCancelDecode();
+ super.cancel(true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index c182209..b9a2b62 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -16,149 +16,205 @@
package com.android.launcher2;
-import java.util.ArrayList;
-import java.util.HashSet;
+import com.android.launcher.R;
+import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.AlertDialog;
import android.app.WallpaperManager;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
+import android.content.ClipData;
+import android.content.ClipDescription;
import android.content.ComponentName;
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;
+import android.graphics.Camera;
import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
import android.graphics.Rect;
+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.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
+import android.view.Display;
+import android.view.DragEvent;
import android.view.MotionEvent;
-import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.animation.Interpolator;
-import android.widget.Scroller;
+import android.view.animation.DecelerateInterpolator;
import android.widget.TextView;
+import android.widget.Toast;
-import com.android.launcher.R;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
/**
- * The workspace is a wide area with a wallpaper and a finite number of screens. Each
- * screen contains a number of icons, folders or widgets the user can interact with.
- * A workspace is meant to be used with a fixed width only.
+ * The workspace is a wide area with a wallpaper and a finite number of pages.
+ * Each page contains a number of icons, folders or widgets the user can
+ * interact with. A workspace is meant to be used with a fixed width only.
*/
-public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller {
+public class Workspace extends SmoothPagedView
+ implements DropTarget, DragSource, DragScroller, View.OnTouchListener {
@SuppressWarnings({"UnusedDeclaration"})
private static final String TAG = "Launcher.Workspace";
- private static final int INVALID_SCREEN = -1;
-
- /**
- * The velocity at which a fling gesture will cause us to snap to the next screen
- */
- private static final int SNAP_VELOCITY = 600;
+
+ // This is how much the workspace shrinks when we enter all apps or
+ // customization mode
+ private static final float SHRINK_FACTOR = 0.16f;
+
+ // How much the screens shrink when we enter spring loaded drag mode
+ private static final float SPRING_LOADED_DRAG_SHRINK_FACTOR = 0.7f;
+
+ // Y rotation to apply to the workspace screens
+ private static final float WORKSPACE_ROTATION = 12.5f;
+
+ // These are extra scale factors to apply to the mini home screens
+ // so as to achieve the desired transform
+ private static final float EXTRA_SCALE_FACTOR_0 = 0.972f;
+ private static final float EXTRA_SCALE_FACTOR_1 = 1.0f;
+ private static final float EXTRA_SCALE_FACTOR_2 = 1.10f;
+
+ private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
+ private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
+ private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
+
+ private static final int BACKGROUND_FADE_OUT_DURATION = 350;
+ private static final int BACKGROUND_FADE_IN_DURATION = 350;
+
+ // These animators are used to fade the children's outlines
+ private ObjectAnimator mChildrenOutlineFadeInAnimation;
+ private ObjectAnimator mChildrenOutlineFadeOutAnimation;
+ private float mChildrenOutlineAlpha = 0;
+
+ // These properties refer to the background protection gradient used for AllApps and Customize
+ private ObjectAnimator mBackgroundFadeInAnimation;
+ private ObjectAnimator mBackgroundFadeOutAnimation;
+ private Drawable mBackground;
+ private Drawable mCustomizeTrayBackground;
+ private boolean mDrawCustomizeTrayBackground;
+ private float mBackgroundAlpha = 0;
+ private float mOverScrollMaxBackgroundAlpha = 0.0f;
+ private int mOverScrollPageIndex = -1;
+
+ private View mCustomizationDrawer;
+ private View mCustomizationDrawerContent;
+ private int[] mCustomizationDrawerPos = new int[2];
+ private float[] mCustomizationDrawerTransformedPos = new float[2];
private final WallpaperManager mWallpaperManager;
-
- private int mDefaultScreen;
- private boolean mFirstLayout = true;
+ private int mDefaultPage;
- private int mCurrentScreen;
- private int mNextScreen = INVALID_SCREEN;
- private Scroller mScroller;
- private VelocityTracker mVelocityTracker;
+ private boolean mPageMoving = false;
+ private boolean mIsDragInProcess = false;
/**
* CellInfo for the cell that is currently being dragged
*/
private CellLayout.CellInfo mDragInfo;
-
+
/**
* Target drop area calculated during last acceptDrop call.
*/
private int[] mTargetCell = null;
- private float mLastMotionX;
- private float mLastMotionY;
-
- private final static int TOUCH_STATE_REST = 0;
- private final static int TOUCH_STATE_SCROLLING = 1;
-
- private int mTouchState = TOUCH_STATE_REST;
-
- private OnLongClickListener mLongClickListener;
+ /**
+ * The CellLayout that is currently being dragged over
+ */
+ private CellLayout mDragTargetLayout = null;
private Launcher mLauncher;
private IconCache mIconCache;
private DragController mDragController;
-
- /**
- * Cache of vacant cells, used during drag events and invalidated as needed.
- */
- private CellLayout.CellInfo mVacantCache = null;
-
+
+ // These are temporary variables to prevent having to allocate a new object just to
+ // 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[] mTempDragCoordinates = new float[2];
+ private float[] mTempTouchCoordinates = new float[2];
+ private float[] mTempCellLayoutCenterCoordinates = new float[2];
+ private float[] mTempDragBottomRightCoordinates = new float[2];
+ private Matrix mTempInverseMatrix = new Matrix();
- private boolean mAllowLongPress = true;
+ private SpringLoadedDragController mSpringLoadedDragController;
- private int mTouchSlop;
- private int mMaximumVelocity;
-
- private static final int INVALID_POINTER = -1;
+ private static final int DEFAULT_CELL_COUNT_X = 4;
+ private static final int DEFAULT_CELL_COUNT_Y = 4;
- private int mActivePointerId = INVALID_POINTER;
-
private Drawable mPreviousIndicator;
private Drawable mNextIndicator;
-
- private static final float NANOTIME_DIV = 1000000000.0f;
- private static final float SMOOTHING_SPEED = 0.75f;
- private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
- private float mSmoothingTime;
- private float mTouchX;
- private WorkspaceOvershootInterpolator mScrollInterpolator;
+ // State variable that indicates whether the pages are small (ie when you're
+ // in all apps or customize mode)
+ private boolean mIsSmall = false;
+ private boolean mIsInUnshrinkAnimation = false;
+ private AnimatorListener mShrinkAnimationListener;
+ private AnimatorListener mUnshrinkAnimationListener;
+ enum ShrinkState { TOP, SPRING_LOADED, MIDDLE, BOTTOM_HIDDEN, BOTTOM_VISIBLE };
+ private ShrinkState mShrinkState;
+ private boolean mWasSpringLoadedOnDragExit = false;
+ private boolean mWaitingToShrink = false;
+ private ShrinkState mWaitingToShrinkState;
+ private AnimatorSet mAnimator;
- private static final float BASELINE_FLING_VELOCITY = 2500.f;
- private static final float FLING_VELOCITY_INFLUENCE = 0.4f;
-
- private static class WorkspaceOvershootInterpolator implements Interpolator {
- private static final float DEFAULT_TENSION = 1.3f;
- private float mTension;
+ /** Is the user is dragging an item near the edge of a page? */
+ private boolean mInScrollArea = false;
- public WorkspaceOvershootInterpolator() {
- mTension = DEFAULT_TENSION;
- }
-
- public void setDistance(int distance) {
- mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
- }
+ /** If mInScrollArea is true, the direction of the scroll. */
+ private int mPendingScrollDirection = DragController.SCROLL_NONE;
- public void disableSettle() {
- mTension = 0.f;
- }
+ private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper();
+ private Bitmap mDragOutline = null;
+ private final Rect mTempRect = new Rect();
+ private final int[] mTempXY = new int[2];
- public float getInterpolation(float t) {
- // _o(t) = t * t * ((tension + 1) * t + tension)
- // o(t) = _o(t - 1) + 1
- t -= 1.0f;
- return t * t * ((mTension + 1) * t + mTension) + 1.0f;
- }
- }
-
+ private ValueAnimator mDropAnim = null;
+ private TimeInterpolator mQuintEaseOutInterpolator = new DecelerateInterpolator(2.5f);
+ private View mDropView = null;
+ private int[] mDropViewPos = new int[] { -1, -1 };
+
+ // Paint used to draw external drop outline
+ private final Paint mExternalDragOutlinePaint = new Paint();
+
+ // Camera and Matrix used to determine the final position of a neighboring CellLayout
+ private final Matrix mMatrix = new Matrix();
+ private final Camera mCamera = new Camera();
+ private final float mTempFloat2[] = new float[2];
+
+ enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM };
+ int mWallpaperWidth;
+ int mWallpaperHeight;
+ WallpaperOffsetInterpolator mWallpaperOffset;
+ boolean mUpdateWallpaperOffsetImmediately = false;
+ boolean mSyncWallpaperOffsetWithScroll = true;
+
/**
* Used to inflate the Workspace from XML.
*
* @param context The application's context.
- * @param attrs The attribtues set containing the Workspace's customization values.
+ * @param attrs The attributes set containing the Workspace's customization values.
*/
public Workspace(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -168,37 +224,91 @@
* Used to inflate the Workspace from XML.
*
* @param context The application's context.
- * @param attrs The attribtues set containing the Workspace's customization values.
+ * @param attrs The attributes set containing the Workspace's customization values.
* @param defStyle Unused.
*/
public Workspace(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ mContentIsRefreshable = false;
+
+ if (!LauncherApplication.isScreenXLarge()) {
+ mFadeInAdjacentScreens = false;
+ }
mWallpaperManager = WallpaperManager.getInstance(context);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0);
- mDefaultScreen = a.getInt(R.styleable.Workspace_defaultScreen, 1);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.Workspace, defStyle, 0);
+ int cellCountX = a.getInt(R.styleable.Workspace_cellCountX, DEFAULT_CELL_COUNT_X);
+ int cellCountY = a.getInt(R.styleable.Workspace_cellCountY, DEFAULT_CELL_COUNT_Y);
+ mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);
a.recycle();
+ LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY);
setHapticFeedbackEnabled(false);
+
initWorkspace();
}
/**
* Initializes various states for this workspace.
*/
- private void initWorkspace() {
+ protected void initWorkspace() {
Context context = getContext();
- mScrollInterpolator = new WorkspaceOvershootInterpolator();
- mScroller = new Scroller(context, mScrollInterpolator);
- mCurrentScreen = mDefaultScreen;
- Launcher.setScreen(mCurrentScreen);
+ mCurrentPage = mDefaultPage;
+ Launcher.setScreen(mCurrentPage);
LauncherApplication app = (LauncherApplication)context.getApplicationContext();
mIconCache = app.getIconCache();
+ mExternalDragOutlinePaint.setAntiAlias(true);
+ setWillNotDraw(false);
- final ViewConfiguration configuration = ViewConfiguration.get(getContext());
- mTouchSlop = configuration.getScaledTouchSlop();
- mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
+ try {
+ final Resources res = getResources();
+ mBackground = res.getDrawable(R.drawable.all_apps_bg_gradient);
+ mCustomizeTrayBackground = res.getDrawable(R.drawable.customize_bg_gradient);
+ } catch (Resources.NotFoundException e) {
+ // In this case, we will skip drawing background protection
+ }
+
+ mUnshrinkAnimationListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsInUnshrinkAnimation = true;
+ disableCacheUpdates();
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsInUnshrinkAnimation = false;
+ mSyncWallpaperOffsetWithScroll = true;
+ if (mShrinkState != ShrinkState.SPRING_LOADED) {
+ mDrawCustomizeTrayBackground = false;
+ }
+ enableCacheUpdates();
+ mAnimator = null;
+ }
+ };
+ mShrinkAnimationListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ disableCacheUpdates();
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ enableCacheUpdates();
+ mAnimator = null;
+ }
+ };
+ mSnapVelocity = 600;
+ mWallpaperOffset = new WallpaperOffsetInterpolator();
+ }
+
+ @Override
+ protected int getScrollMode() {
+ if (LauncherApplication.isScreenXLarge()) {
+ return SmoothPagedView.X_LARGE_MODE;
+ } else {
+ return SmoothPagedView.DEFAULT_MODE;
+ }
}
@Override
@@ -206,6 +316,7 @@
if (!(child instanceof CellLayout)) {
throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
}
+ ((CellLayout) child).setOnInterceptTouchListener(this);
super.addView(child, index, params);
}
@@ -214,6 +325,7 @@
if (!(child instanceof CellLayout)) {
throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
}
+ ((CellLayout) child).setOnInterceptTouchListener(this);
super.addView(child);
}
@@ -222,6 +334,7 @@
if (!(child instanceof CellLayout)) {
throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
}
+ ((CellLayout) child).setOnInterceptTouchListener(this);
super.addView(child, index);
}
@@ -230,6 +343,7 @@
if (!(child instanceof CellLayout)) {
throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
}
+ ((CellLayout) child).setOnInterceptTouchListener(this);
super.addView(child, width, height);
}
@@ -238,6 +352,7 @@
if (!(child instanceof CellLayout)) {
throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
}
+ ((CellLayout) child).setOnInterceptTouchListener(this);
super.addView(child, params);
}
@@ -245,94 +360,41 @@
* @return The open folder on the current screen, or null if there is none
*/
Folder getOpenFolder() {
- CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);
- int count = currentScreen.getChildCount();
+ CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
+ int count = currentPage.getChildCount();
for (int i = 0; i < count; i++) {
- View child = currentScreen.getChildAt(i);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
- return (Folder) child;
+ View child = currentPage.getChildAt(i);
+ if (child instanceof Folder) {
+ Folder folder = (Folder) child;
+ if (folder.getInfo().opened)
+ return folder;
}
}
return null;
}
ArrayList<Folder> getOpenFolders() {
- final int screens = getChildCount();
- ArrayList<Folder> folders = new ArrayList<Folder>(screens);
+ final int screenCount = getChildCount();
+ ArrayList<Folder> folders = new ArrayList<Folder>(screenCount);
- for (int screen = 0; screen < screens; screen++) {
- CellLayout currentScreen = (CellLayout) getChildAt(screen);
- int count = currentScreen.getChildCount();
+ for (int screen = 0; screen < screenCount; screen++) {
+ CellLayout currentPage = (CellLayout) getChildAt(screen);
+ int count = currentPage.getChildCount();
for (int i = 0; i < count; i++) {
- View child = currentScreen.getChildAt(i);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
- folders.add((Folder) child);
+ View child = currentPage.getChildAt(i);
+ if (child instanceof Folder) {
+ Folder folder = (Folder) child;
+ if (folder.getInfo().opened)
+ folders.add(folder);
break;
}
}
}
-
return folders;
}
- boolean isDefaultScreenShowing() {
- return mCurrentScreen == mDefaultScreen;
- }
-
- /**
- * Returns the index of the currently displayed screen.
- *
- * @return The index of the currently displayed screen.
- */
- int getCurrentScreen() {
- return mCurrentScreen;
- }
-
- /**
- * Sets the current screen.
- *
- * @param currentScreen
- */
- void setCurrentScreen(int currentScreen) {
- if (!mScroller.isFinished()) mScroller.abortAnimation();
- clearVacantCache();
- mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
- mPreviousIndicator.setLevel(mCurrentScreen);
- mNextIndicator.setLevel(mCurrentScreen);
- scrollTo(mCurrentScreen * getWidth(), 0);
- updateWallpaperOffset();
- invalidate();
- }
-
- /**
- * Adds the specified child in the current screen. The position and dimension of
- * the child are defined by x, y, spanX and spanY.
- *
- * @param child The child to add in one of the workspace's screens.
- * @param x The X position of the child in the screen's grid.
- * @param y The Y position of the child in the screen's grid.
- * @param spanX The number of cells spanned horizontally by the child.
- * @param spanY The number of cells spanned vertically by the child.
- */
- void addInCurrentScreen(View child, int x, int y, int spanX, int spanY) {
- addInScreen(child, mCurrentScreen, x, y, spanX, spanY, false);
- }
-
- /**
- * Adds the specified child in the current screen. The position and dimension of
- * the child are defined by x, y, spanX and spanY.
- *
- * @param child The child to add in one of the workspace's screens.
- * @param x The X position of the child in the screen's grid.
- * @param y The Y position of the child in the screen's grid.
- * @param spanX The number of cells spanned horizontally by the child.
- * @param spanY The number of cells spanned vertically by the child.
- * @param insert When true, the child is inserted at the beginning of the children list.
- */
- void addInCurrentScreen(View child, int x, int y, int spanX, int spanY, boolean insert) {
- addInScreen(child, mCurrentScreen, x, y, spanX, spanY, insert);
+ boolean isDefaultPageShowing() {
+ return mCurrentPage == mDefaultPage;
}
/**
@@ -350,6 +412,10 @@
addInScreen(child, screen, x, y, spanX, spanY, false);
}
+ void addInFullScreen(View child, int screen) {
+ addInScreen(child, screen, 0, 0, -1, -1);
+ }
+
/**
* Adds the specified child in the specified screen. The position and dimension of
* the child are defined by x, y, spanX and spanY.
@@ -369,8 +435,6 @@
return;
}
- clearVacantCache();
-
final CellLayout group = (CellLayout) getChildAt(screen);
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
if (lp == null) {
@@ -381,124 +445,502 @@
lp.cellHSpan = spanX;
lp.cellVSpan = spanY;
}
- group.addView(child, insert ? 0 : -1, lp);
+
+ // 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);
+ if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
+ // TODO: This branch occurs when the workspace is adding views
+ // outside of the defined grid
+ // maybe we should be deleting these items from the LauncherModel?
+ Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
+ }
+
if (!(child instanceof Folder)) {
child.setHapticFeedbackEnabled(false);
child.setOnLongClickListener(mLongClickListener);
}
if (child instanceof DropTarget) {
- mDragController.addDropTarget((DropTarget)child);
- }
- }
-
- CellLayout.CellInfo findAllVacantCells(boolean[] occupied) {
- CellLayout group = (CellLayout) getChildAt(mCurrentScreen);
- if (group != null) {
- return group.findAllVacantCells(occupied, null);
- }
- return null;
- }
-
- private void clearVacantCache() {
- if (mVacantCache != null) {
- mVacantCache.clearVacantCells();
- mVacantCache = null;
+ mDragController.addDropTarget((DropTarget) child);
}
}
/**
- * Registers the specified listener on each screen contained in this workspace.
- *
- * @param l The listener used to respond to long clicks.
+ * Check if the point (x, y) hits a given page.
*/
+ private boolean hitsPage(int index, float x, float y) {
+ final View page = getChildAt(index);
+ if (page != null) {
+ float[] localXY = { x, y };
+ mapPointFromSelfToChild(page, localXY);
+ return (localXY[0] >= 0 && localXY[0] < page.getWidth()
+ && localXY[1] >= 0 && localXY[1] < page.getHeight());
+ }
+ return false;
+ }
+
@Override
- public void setOnLongClickListener(OnLongClickListener l) {
- mLongClickListener = l;
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- getChildAt(i).setOnLongClickListener(l);
+ protected boolean hitsPreviousPage(float x, float y) {
+ // mNextPage is set to INVALID_PAGE whenever we are stationary.
+ // Calculating "next page" this way ensures that you scroll to whatever page you tap on
+ final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
+ return hitsPage(current - 1, x, y);
+ }
+
+ @Override
+ protected boolean hitsNextPage(float x, float y) {
+ // mNextPage is set to INVALID_PAGE whenever we are stationary.
+ // Calculating "next page" this way ensures that you scroll to whatever page you tap on
+ final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
+ return hitsPage(current + 1, x, y);
+ }
+
+ public boolean onTouch(View v, MotionEvent event) {
+ // this is an intercepted event being forwarded from a cell layout
+ if (mIsSmall || mIsInUnshrinkAnimation) {
+ // Only allow clicks on a CellLayout if it is visible
+ if (mShrinkState != ShrinkState.BOTTOM_HIDDEN) {
+ mLauncher.onWorkspaceClick((CellLayout) v);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ protected void onWindowVisibilityChanged (int visibility) {
+ mLauncher.onWindowVisibilityChanged(visibility);
+ }
+
+ @Override
+ public boolean dispatchUnhandledMove(View focused, int direction) {
+ if (mIsSmall || mIsInUnshrinkAnimation) {
+ // when the home screens are shrunken, shouldn't allow side-scrolling
+ return false;
+ }
+ return super.dispatchUnhandledMove(focused, direction);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mIsSmall || mIsInUnshrinkAnimation) {
+ if (mLauncher.isAllAppsVisible() &&
+ mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
+ // Intercept this event so we can show the workspace in full view
+ // when it is clicked on and it is small
+ return true;
+ }
+ return false;
+ }
+ return super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ protected void determineScrollingStart(MotionEvent ev) {
+ if (!mIsSmall && !mIsInUnshrinkAnimation) super.determineScrollingStart(ev);
+ }
+
+ protected void onPageBeginMoving() {
+ if (mNextPage != INVALID_PAGE) {
+ // we're snapping to a particular screen
+ enableChildrenCache(mCurrentPage, mNextPage);
+ } else {
+ // this is when user is actively dragging a particular screen, they might
+ // swipe it either left or right (but we won't advance by more than one screen)
+ enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
+ }
+ showOutlines();
+ mPageMoving = true;
+ }
+
+ protected void onPageEndMoving() {
+ clearChildrenCache();
+ // Hide the outlines, as long as we're not dragging
+ if (!mDragController.dragging()) {
+ hideOutlines();
+ }
+ mOverScrollMaxBackgroundAlpha = 0.0f;
+ mOverScrollPageIndex = -1;
+ mPageMoving = false;
+ }
+
+ @Override
+ protected void notifyPageSwitchListener() {
+ super.notifyPageSwitchListener();
+
+ if (mPreviousIndicator != null) {
+ // if we know the next page, we show the indication for it right away; it looks
+ // weird if the indicators are lagging
+ int page = mNextPage;
+ if (page == INVALID_PAGE) {
+ page = mCurrentPage;
+ }
+ mPreviousIndicator.setLevel(page);
+ mNextIndicator.setLevel(page);
+ }
+ Launcher.setScreen(mCurrentPage);
+ };
+
+ // As a ratio of screen height, the total distance we want the parallax effect to span
+ // vertically
+ private float wallpaperTravelToScreenHeightRatio(int width, int height) {
+ return 1.1f;
+ }
+
+ // As a ratio of screen height, the total distance we want the parallax effect to span
+ // horizontally
+ private float wallpaperTravelToScreenWidthRatio(int width, int height) {
+ float aspectRatio = width / (float) height;
+
+ // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
+ // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
+ // We will use these two data points to extrapolate how much the wallpaper parallax effect
+ // to span (ie travel) at any aspect ratio:
+
+ final float ASPECT_RATIO_LANDSCAPE = 16/10f;
+ final float ASPECT_RATIO_PORTRAIT = 10/16f;
+ final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
+ final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
+
+ // To find out the desired width at different aspect ratios, we use the following two
+ // formulas, where the coefficient on x is the aspect ratio (width/height):
+ // (16/10)x + y = 1.5
+ // (10/16)x + y = 1.2
+ // We solve for x and y and end up with a final formula:
+ final float x =
+ (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
+ (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
+ final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
+ return x * aspectRatio + y;
+ }
+
+ // The range of scroll values for Workspace
+ private int getScrollRange() {
+ return getChildOffset(getChildCount() - 1) - getChildOffset(0);
+ }
+
+ protected void setWallpaperDimension() {
+ Display display = mLauncher.getWindowManager().getDefaultDisplay();
+ final int maxDim = Math.max(display.getWidth(), display.getHeight());
+ final int minDim = Math.min(display.getWidth(), display.getHeight());
+
+ // We need to ensure that there is enough extra space in the wallpaper for the intended
+ // parallax effects
+ mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+ mWallpaperHeight = (int)(maxDim * wallpaperTravelToScreenHeightRatio(maxDim, minDim));
+ mWallpaperManager.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight);
+ }
+
+ public void setVerticalWallpaperOffset(float offset) {
+ mWallpaperOffset.setFinalY(offset);
+ }
+ public float getVerticalWallpaperOffset() {
+ return mWallpaperOffset.getCurrY();
+ }
+ public void setHorizontalWallpaperOffset(float offset) {
+ mWallpaperOffset.setFinalX(offset);
+ }
+ public float getHorizontalWallpaperOffset() {
+ return mWallpaperOffset.getCurrX();
+ }
+
+ private float wallpaperOffsetForCurrentScroll() {
+ Display display = mLauncher.getWindowManager().getDefaultDisplay();
+ // The wallpaper travel width is how far, from left to right, the wallpaper will move
+ // at this orientation (for example, in portrait mode we don't move all the way to the
+ // edges of the wallpaper, or otherwise the parallax effect would be too strong)
+ int wallpaperTravelWidth = (int) (display.getWidth() *
+ wallpaperTravelToScreenWidthRatio(display.getWidth(), display.getHeight()));
+
+ // Account for overscroll: you only see the absolute edge of the wallpaper if
+ // you overscroll as far as you can in landscape mode
+ int overscrollOffset = (int) (maxOverScroll() * display.getWidth());
+ float overscrollRatio = overscrollOffset / (float) getScrollRange();
+ int scrollRangeWithOverscroll = getScrollRange() + 2 * overscrollOffset;
+
+ // Set wallpaper offset steps (1 / (number of screens - 1))
+ // We have 3 vertical offset states (centered, and then top/bottom aligned
+ // for all apps/customize)
+ mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f / (3 - 1));
+
+ float scrollProgress =
+ mScrollX / (float) scrollRangeWithOverscroll + overscrollRatio;
+ float offsetInDips = wallpaperTravelWidth * scrollProgress +
+ (mWallpaperWidth - wallpaperTravelWidth) / 2;
+ float offset = offsetInDips / (float) mWallpaperWidth;
+ return offset;
+ }
+ private void syncWallpaperOffsetWithScroll() {
+ if (LauncherApplication.isScreenXLarge()) {
+ mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());
}
}
- private void updateWallpaperOffset() {
- updateWallpaperOffset(getChildAt(getChildCount() - 1).getRight() - (mRight - mLeft));
+ public void updateWallpaperOffsetImmediately() {
+ mUpdateWallpaperOffsetImmediately = true;
}
- private void updateWallpaperOffset(int scrollRange) {
- IBinder token = getWindowToken();
- if (token != null) {
- mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 );
- mWallpaperManager.setWallpaperOffsets(getWindowToken(),
- Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0);
+ private void updateWallpaperOffsets() {
+ boolean updateNow = false;
+ boolean keepUpdating = true;
+ if (mUpdateWallpaperOffsetImmediately) {
+ updateNow = true;
+ keepUpdating = false;
+ mWallpaperOffset.jumpToFinal();
+ mUpdateWallpaperOffsetImmediately = false;
+ } else {
+ updateNow = keepUpdating = mWallpaperOffset.computeScrollOffset();
+ }
+ if (updateNow) {
+ IBinder token = getWindowToken();
+ if (token != null) {
+ mWallpaperManager.setWallpaperOffsets(getWindowToken(),
+ mWallpaperOffset.getCurrX(), mWallpaperOffset.getCurrY());
+ }
+ }
+ if (keepUpdating) {
+ invalidate();
}
}
-
- @Override
- public void scrollTo(int x, int y) {
- super.scrollTo(x, y);
- mTouchX = x;
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+
+ class WallpaperOffsetInterpolator {
+ float mFinalHorizontalWallpaperOffset = 0.0f;
+ float mFinalVerticalWallpaperOffset = 0.5f;
+ float mHorizontalWallpaperOffset = 0.0f;
+ float mVerticalWallpaperOffset = 0.5f;
+ long mLastWallpaperOffsetUpdateTime;
+
+ public WallpaperOffsetInterpolator() {
+ }
+
+ public boolean computeScrollOffset() {
+ if (Float.compare(mHorizontalWallpaperOffset, mFinalHorizontalWallpaperOffset) == 0 &&
+ Float.compare(mVerticalWallpaperOffset, mFinalVerticalWallpaperOffset) == 0) {
+ return false;
+ }
+ Display display = mLauncher.getWindowManager().getDefaultDisplay();
+ boolean isLandscape = display.getWidth() > display.getHeight();
+
+ long currentTime = System.currentTimeMillis();
+ long timeSinceLastUpdate = currentTime - mLastWallpaperOffsetUpdateTime;
+ timeSinceLastUpdate = Math.min((long) (1000/30f), timeSinceLastUpdate);
+ timeSinceLastUpdate = Math.max(1L, timeSinceLastUpdate);
+ // ie 75% in 100ms
+ float fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.75f / 100 : 0.75f / 100;
+ float fractionToCatchUpIn1MsVertical = isLandscape ? 1.1f / 100 : 1.1f / 100;
+
+ final float UPDATE_THRESHOLD = 0.00001f;
+ float hOffsetDelta = mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset;
+ float vOffsetDelta = mFinalVerticalWallpaperOffset - mVerticalWallpaperOffset;
+ boolean jumpToFinalValue =
+ Math.abs(hOffsetDelta / mFinalHorizontalWallpaperOffset) < UPDATE_THRESHOLD &&
+ Math.abs(vOffsetDelta / mFinalVerticalWallpaperOffset) < UPDATE_THRESHOLD;
+ if (jumpToFinalValue) {
+ mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
+ mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
+ } else {
+ float percentToCatchUpVertical =
+ timeSinceLastUpdate * fractionToCatchUpIn1MsVertical;
+ float percentToCatchUpHorizontal =
+ timeSinceLastUpdate * fractionToCatchUpIn1MsHorizontal;
+ mHorizontalWallpaperOffset += percentToCatchUpHorizontal * hOffsetDelta;
+ mVerticalWallpaperOffset += percentToCatchUpVertical * vOffsetDelta;
+ }
+ mLastWallpaperOffsetUpdateTime = System.currentTimeMillis();
+ return true;
+ }
+
+ public float getCurrX() {
+ return mHorizontalWallpaperOffset;
+ }
+
+ public float getFinalX() {
+ return mFinalHorizontalWallpaperOffset;
+ }
+
+ public float getCurrY() {
+ return mVerticalWallpaperOffset;
+ }
+
+ public float getFinalY() {
+ return mFinalVerticalWallpaperOffset;
+ }
+
+ public void setFinalX(float x) {
+ mFinalHorizontalWallpaperOffset = Math.max(0f, Math.min(x, 1.0f));
+ }
+
+ public void setFinalY(float y) {
+ mFinalVerticalWallpaperOffset = Math.max(0f, Math.min(y, 1.0f));
+ }
+
+ public void jumpToFinal() {
+ mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
+ mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
+ }
}
-
+
@Override
public void computeScroll() {
- if (mScroller.computeScrollOffset()) {
- mTouchX = mScrollX = mScroller.getCurrX();
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
- mScrollY = mScroller.getCurrY();
- updateWallpaperOffset();
- postInvalidate();
- } else if (mNextScreen != INVALID_SCREEN) {
- mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
- mPreviousIndicator.setLevel(mCurrentScreen);
- mNextIndicator.setLevel(mCurrentScreen);
- Launcher.setScreen(mCurrentScreen);
- mNextScreen = INVALID_SCREEN;
- clearChildrenCache();
- } else if (mTouchState == TOUCH_STATE_SCROLLING) {
- final float now = System.nanoTime() / NANOTIME_DIV;
- final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
- final float dx = mTouchX - mScrollX;
- mScrollX += dx * e;
- mSmoothingTime = now;
-
- // Keep generating points as long as we're more than 1px away from the target
- if (dx > 1.f || dx < -1.f) {
- updateWallpaperOffset();
- postInvalidate();
- }
+ super.computeScroll();
+ if (mSyncWallpaperOffsetWithScroll) {
+ syncWallpaperOffsetWithScroll();
}
}
- @Override
- protected void dispatchDraw(Canvas canvas) {
- boolean restore = false;
- int restoreCount = 0;
+ public void showOutlines() {
+ if (!mIsSmall && !mIsInUnshrinkAnimation) {
+ if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
+ if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
+ mChildrenOutlineFadeInAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 1.0f);
+ mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
+ mChildrenOutlineFadeInAnimation.start();
+ }
+ }
- // ViewGroup.dispatchDraw() supports many features we don't need:
- // clip to padding, layout animation, animation listener, disappearing
- // children, etc. The following implementation attempts to fast-track
- // the drawing dispatch by drawing only what we know needs to be drawn.
+ public void hideOutlines() {
+ if (!mIsSmall && !mIsInUnshrinkAnimation) {
+ if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
+ if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
+ mChildrenOutlineFadeOutAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 0.0f);
+ mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
+ mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
+ mChildrenOutlineFadeOutAnimation.start();
+ }
+ }
- boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN;
- // If we are not scrolling or flinging, draw only the current screen
- if (fastDraw) {
- drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime());
+ public void setChildrenOutlineAlpha(float alpha) {
+ mChildrenOutlineAlpha = alpha;
+ for (int i = 0; i < getChildCount(); i++) {
+ CellLayout cl = (CellLayout) getChildAt(i);
+ cl.setBackgroundAlpha(alpha);
+ }
+ }
+
+ public float getChildrenOutlineAlpha() {
+ return mChildrenOutlineAlpha;
+ }
+
+ private void showBackgroundGradientForAllApps() {
+ showBackgroundGradient();
+ mDrawCustomizeTrayBackground = false;
+ }
+
+ private void showBackgroundGradientForCustomizeTray() {
+ showBackgroundGradient();
+ mDrawCustomizeTrayBackground = true;
+ }
+
+ private void showBackgroundGradient() {
+ if (mBackground == null) return;
+ if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel();
+ if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel();
+ mBackgroundFadeInAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 1.0f);
+ mBackgroundFadeInAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
+ mBackgroundFadeInAnimation.setDuration(BACKGROUND_FADE_IN_DURATION);
+ mBackgroundFadeInAnimation.start();
+ }
+
+ private void hideBackgroundGradient() {
+ if (mBackground == null) return;
+ if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel();
+ if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel();
+ mBackgroundFadeOutAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 0.0f);
+ mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
+ mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
+ mBackgroundFadeOutAnimation.start();
+ }
+
+ public void setBackgroundAlpha(float alpha) {
+ mBackgroundAlpha = alpha;
+ invalidate();
+ }
+
+ public float getBackgroundAlpha() {
+ return mBackgroundAlpha;
+ }
+
+ /**
+ * Due to 3D transformations, if two CellLayouts are theoretically touching each other,
+ * on the xy plane, when one is rotated along the y-axis, the gap between them is perceived
+ * as being larger. This method computes what offset the rotated view should be translated
+ * in order to minimize this perceived gap.
+ * @param degrees Angle of the view
+ * @param width Width of the view
+ * @param height Height of the view
+ * @return Offset to be used in a View.setTranslationX() call
+ */
+ private float getOffsetXForRotation(float degrees, int width, int height) {
+ mMatrix.reset();
+ mCamera.save();
+ mCamera.rotateY(Math.abs(degrees));
+ mCamera.getMatrix(mMatrix);
+ mCamera.restore();
+
+ mMatrix.preTranslate(-width * 0.5f, -height * 0.5f);
+ mMatrix.postTranslate(width * 0.5f, height * 0.5f);
+ mTempFloat2[0] = width;
+ mTempFloat2[1] = height;
+ mMatrix.mapPoints(mTempFloat2);
+ return (width - mTempFloat2[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
+ }
+
+ float backgroundAlphaInterpolator(float r) {
+ float pivotA = 0.1f;
+ float pivotB = 0.4f;
+ if (r < pivotA) {
+ return 0;
+ } else if (r > pivotB) {
+ return 1.0f;
} else {
- final long drawingTime = getDrawingTime();
- final float scrollPos = (float) mScrollX / getWidth();
- final int leftScreen = (int) scrollPos;
- final int rightScreen = leftScreen + 1;
- if (leftScreen >= 0) {
- drawChild(canvas, getChildAt(leftScreen), drawingTime);
- }
- if (scrollPos != leftScreen && rightScreen < getChildCount()) {
- drawChild(canvas, getChildAt(rightScreen), drawingTime);
- }
+ return (r - pivotA)/(pivotB - pivotA);
+ }
+ }
+
+ float overScrollBackgroundAlphaInterpolator(float r) {
+ float threshold = 0.08f;
+
+ if (r > mOverScrollMaxBackgroundAlpha) {
+ mOverScrollMaxBackgroundAlpha = r;
+ } else if (r < mOverScrollMaxBackgroundAlpha) {
+ r = mOverScrollMaxBackgroundAlpha;
}
- if (restore) {
- canvas.restoreToCount(restoreCount);
+ return Math.min(r / threshold, 1.0f);
+ }
+
+ @Override
+ protected void screenScrolled(int screenCenter) {
+ final int halfScreenSize = getMeasuredWidth() / 2;
+
+ for (int i = 0; i < getChildCount(); i++) {
+ CellLayout cl = (CellLayout) getChildAt(i);
+ if (cl != null) {
+ int totalDistance = getScaledMeasuredWidth(cl) + mPageSpacing;
+ int delta = screenCenter - (getChildOffset(i) -
+ getRelativeChildOffset(i) + halfScreenSize);
+
+ float scrollProgress = delta / (totalDistance * 1.0f);
+ scrollProgress = Math.min(scrollProgress, 1.0f);
+ scrollProgress = Math.max(scrollProgress, -1.0f);
+
+ // If the current page (i) is being overscrolled, we use a different
+ // set of rules for setting the background alpha multiplier.
+ if ((mScrollX < 0 && i == 0) || (mScrollX > mMaxScrollX &&
+ i == getChildCount() -1 )) {
+ cl.setBackgroundAlphaMultiplier(
+ overScrollBackgroundAlphaInterpolator(Math.abs(scrollProgress)));
+ mOverScrollPageIndex = i;
+ } else if (mOverScrollPageIndex != i) {
+ cl.setBackgroundAlphaMultiplier(
+ backgroundAlphaInterpolator(Math.abs(scrollProgress)));
+ }
+
+ float rotation = WORKSPACE_ROTATION * scrollProgress;
+ float translationX = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
+ cl.setTranslationX(translationX);
+
+ cl.setRotationY(rotation);
+ }
}
}
@@ -509,59 +951,135 @@
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
+ mUpdateWallpaperOffsetImmediately = true;
+ }
+ super.onLayout(changed, left, top, right, bottom);
- final int width = MeasureSpec.getSize(widthMeasureSpec);
- final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- if (widthMode != MeasureSpec.EXACTLY) {
- throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
+ // if shrinkToBottom() is called on initialization, it has to be deferred
+ // until after the first call to onLayout so that it has the correct width
+ if (mWaitingToShrink) {
+ // shrink can trigger a synchronous onLayout call, so we
+ // post this to avoid a stack overflow / tangled onLayout calls
+ post(new Runnable() {
+ public void run() {
+ shrink(mWaitingToShrinkState, false);
+ mWaitingToShrink = false;
+ }
+ });
}
- final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- if (heightMode != MeasureSpec.EXACTLY) {
- throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");
+ if (LauncherApplication.isInPlaceRotationEnabled()) {
+ // When the device is rotated, the scroll position of the current screen
+ // needs to be refreshed
+ setCurrentPage(getCurrentPage());
}
+ }
- // The children are given the same width and height as the workspace
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
+ public void enableCacheUpdates() {
+ final int pageCount = getChildCount();
+ for (int i = 0; i < pageCount; i++) {
+ final CellLayout page = (CellLayout) getChildAt(i);
+ page.enableCacheUpdates();
}
+ }
-
- if (mFirstLayout) {
- setHorizontalScrollBarEnabled(false);
- scrollTo(mCurrentScreen * width, 0);
- setHorizontalScrollBarEnabled(true);
- updateWallpaperOffset(width * (getChildCount() - 1));
- mFirstLayout = false;
+ public void disableCacheUpdates() {
+ final int pageCount = getChildCount();
+ for (int i = 0; i < pageCount; i++) {
+ final CellLayout page = (CellLayout) getChildAt(i);
+ page.disableCacheUpdates();
}
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- int childLeft = 0;
+ protected void onDraw(Canvas canvas) {
+ updateWallpaperOffsets();
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() != View.GONE) {
- final int childWidth = child.getMeasuredWidth();
- child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
- childLeft += childWidth;
+ // Draw the background gradient if necessary
+ if (mBackground != null && mBackgroundAlpha > 0.0f) {
+ int alpha = (int) (mBackgroundAlpha * 255);
+ if (mDrawCustomizeTrayBackground) {
+ // Find out where to offset the gradient for the customization tray content
+ mCustomizationDrawer.getLocationOnScreen(mCustomizationDrawerPos);
+ final Matrix m = mCustomizationDrawer.getMatrix();
+ mCustomizationDrawerTransformedPos[0] = 0.0f;
+ mCustomizationDrawerTransformedPos[1] = mCustomizationDrawerContent.getTop();
+ m.mapPoints(mCustomizationDrawerTransformedPos);
+
+ // Draw the bg glow behind the gradient
+ mCustomizeTrayBackground.setAlpha(alpha);
+ mCustomizeTrayBackground.setBounds(mScrollX, 0, mScrollX + getMeasuredWidth(),
+ getMeasuredHeight());
+ mCustomizeTrayBackground.draw(canvas);
+
+ // Draw the bg gradient
+ final int offset = (int) (mCustomizationDrawerPos[1] +
+ mCustomizationDrawerTransformedPos[1]);
+ mBackground.setAlpha(alpha);
+ mBackground.setBounds(mScrollX, offset, mScrollX + getMeasuredWidth(),
+ offset + getMeasuredHeight());
+ mBackground.draw(canvas);
+ } else {
+ mBackground.setAlpha(alpha);
+ mBackground.setBounds(mScrollX, 0, mScrollX + getMeasuredWidth(),
+ getMeasuredHeight());
+ mBackground.draw(canvas);
}
}
+ super.onDraw(canvas);
}
@Override
- public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
- int screen = indexOfChild(child);
- if (screen != mCurrentScreen || !mScroller.isFinished()) {
- snapToScreen(screen);
- return true;
+ protected void dispatchDraw(Canvas canvas) {
+ if (mIsSmall || mIsInUnshrinkAnimation) {
+ // Draw all the workspaces if we're small
+ final int pageCount = getChildCount();
+ final long drawingTime = getDrawingTime();
+ for (int i = 0; i < pageCount; i++) {
+ final View page = (View) getChildAt(i);
+
+ drawChild(canvas, page, drawingTime);
+ }
+ } else {
+ super.dispatchDraw(canvas);
+
+ final int width = getWidth();
+ final int height = getHeight();
+
+ // In portrait orientation, draw the glowing edge when dragging to adjacent screens
+ if (mInScrollArea && (height > width)) {
+ final int pageHeight = getChildAt(0).getHeight();
+
+ // This determines the height of the glowing edge: 90% of the page height
+ final int padding = (int) ((height - pageHeight) * 0.5f + pageHeight * 0.1f);
+
+ final CellLayout leftPage = (CellLayout) getChildAt(mCurrentPage - 1);
+ final CellLayout rightPage = (CellLayout) getChildAt(mCurrentPage + 1);
+
+ if (leftPage != null && leftPage.getIsDragOverlapping()) {
+ final Drawable d = getResources().getDrawable(R.drawable.page_hover_left);
+ d.setBounds(mScrollX, padding, mScrollX + d.getIntrinsicWidth(), height - padding);
+ d.draw(canvas);
+ } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
+ final Drawable d = getResources().getDrawable(R.drawable.page_hover_right);
+ d.setBounds(mScrollX + width - d.getIntrinsicWidth(), padding, mScrollX + width, height - padding);
+ d.draw(canvas);
+ }
+ }
+
+ if (mDropView != null) {
+ // We are animating an item that was just dropped on the home screen.
+ // Render its View in the current animation position.
+ canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ final int xPos = mDropViewPos[0] - mDropView.getScrollX();
+ final int yPos = mDropViewPos[1] - mDropView.getScrollY();
+ canvas.translate(xPos, yPos);
+ mDropView.draw(canvas);
+ canvas.restore();
+ }
}
- return false;
}
@Override
@@ -571,51 +1089,20 @@
if (openFolder != null) {
return openFolder.requestFocus(direction, previouslyFocusedRect);
} else {
- int focusableScreen;
- if (mNextScreen != INVALID_SCREEN) {
- focusableScreen = mNextScreen;
- } else {
- focusableScreen = mCurrentScreen;
- }
- getChildAt(focusableScreen).requestFocus(direction, previouslyFocusedRect);
+ return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
}
}
return false;
}
@Override
- public boolean dispatchUnhandledMove(View focused, int direction) {
- if (direction == View.FOCUS_LEFT) {
- if (getCurrentScreen() > 0) {
- snapToScreen(getCurrentScreen() - 1);
- return true;
- }
- } else if (direction == View.FOCUS_RIGHT) {
- if (getCurrentScreen() < getChildCount() - 1) {
- snapToScreen(getCurrentScreen() + 1);
- return true;
- }
- }
- return super.dispatchUnhandledMove(focused, direction);
- }
-
- @Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
if (!mLauncher.isAllAppsVisible()) {
final Folder openFolder = getOpenFolder();
- if (openFolder == null) {
- getChildAt(mCurrentScreen).addFocusables(views, direction);
- if (direction == View.FOCUS_LEFT) {
- if (mCurrentScreen > 0) {
- getChildAt(mCurrentScreen - 1).addFocusables(views, direction);
- }
- } else if (direction == View.FOCUS_RIGHT){
- if (mCurrentScreen < getChildCount() - 1) {
- getChildAt(mCurrentScreen + 1).addFocusables(views, direction);
- }
- }
- } else {
+ if (openFolder != null) {
openFolder.addFocusables(views, direction);
+ } else {
+ super.addFocusables(views, direction, focusableMode);
}
}
}
@@ -623,195 +1110,29 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- if (mLauncher.isAllAppsVisible()) {
+ // (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);
}
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- final boolean allAppsVisible = mLauncher.isAllAppsVisible();
- if (allAppsVisible) {
- return false; // We don't want the events. Let them fall through to the all apps view.
+ void enableChildrenCache(int fromPage, int toPage) {
+ if (fromPage > toPage) {
+ final int temp = fromPage;
+ fromPage = toPage;
+ toPage = temp;
}
- /*
- * This method JUST determines whether we want to intercept the motion.
- * If we return true, onTouchEvent will be called and we do the actual
- * scrolling there.
- */
+ final int screenCount = getChildCount();
- /*
- * Shortcut the most recurring case: the user is in the dragging
- * state and he is moving his finger. We want to intercept this
- * motion.
- */
- final int action = ev.getAction();
- if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {
- return true;
- }
+ fromPage = Math.max(fromPage, 0);
+ toPage = Math.min(toPage, screenCount - 1);
- acquireVelocityTrackerAndAddMovement(ev);
-
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_MOVE: {
- /*
- * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
- * whether the user has moved far enough from his original down touch.
- */
-
- /*
- * Locally do absolute value. mLastMotionX is set to the y value
- * of the down event.
- */
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- final float x = ev.getX(pointerIndex);
- final float y = ev.getY(pointerIndex);
- final int xDiff = (int) Math.abs(x - mLastMotionX);
- final int yDiff = (int) Math.abs(y - mLastMotionY);
-
- final int touchSlop = mTouchSlop;
- boolean xMoved = xDiff > touchSlop;
- boolean yMoved = yDiff > touchSlop;
-
- if (xMoved || yMoved) {
-
- if (xMoved) {
- // Scroll if the user moved far enough along the X axis
- mTouchState = TOUCH_STATE_SCROLLING;
- mLastMotionX = x;
- mTouchX = mScrollX;
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
- enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);
- }
- // Either way, cancel any pending longpress
- if (mAllowLongPress) {
- mAllowLongPress = false;
- // Try canceling the long press. It could also have been scheduled
- // by a distant descendant, so use the mAllowLongPress flag to block
- // everything
- final View currentScreen = getChildAt(mCurrentScreen);
- currentScreen.cancelLongPress();
- }
- }
- break;
- }
-
- case MotionEvent.ACTION_DOWN: {
- final float x = ev.getX();
- final float y = ev.getY();
- // Remember location of down touch
- mLastMotionX = x;
- mLastMotionY = y;
- mActivePointerId = ev.getPointerId(0);
- mAllowLongPress = true;
-
- /*
- * If being flinged and user touches the screen, initiate drag;
- * otherwise don't. mScroller.isFinished should be false when
- * being flinged.
- */
- mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
- break;
- }
-
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
-
- if (mTouchState != TOUCH_STATE_SCROLLING) {
- final CellLayout currentScreen = (CellLayout)getChildAt(mCurrentScreen);
- if (!currentScreen.lastDownOnOccupiedCell()) {
- getLocationOnScreen(mTempCell);
- // Send a tap to the wallpaper if the last down was on empty space
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- mWallpaperManager.sendWallpaperCommand(getWindowToken(),
- "android.wallpaper.tap",
- mTempCell[0] + (int) ev.getX(pointerIndex),
- mTempCell[1] + (int) ev.getY(pointerIndex), 0, null);
- }
- }
-
- // Release the drag
- clearChildrenCache();
- mTouchState = TOUCH_STATE_REST;
- mActivePointerId = INVALID_POINTER;
- mAllowLongPress = false;
- releaseVelocityTracker();
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- break;
- }
-
- /*
- * The only time we want to intercept motion events is if we are in the
- * drag mode.
- */
- return mTouchState != TOUCH_STATE_REST;
- }
-
- private void onSecondaryPointerUp(MotionEvent ev) {
- final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
- MotionEvent.ACTION_POINTER_INDEX_SHIFT;
- final int pointerId = ev.getPointerId(pointerIndex);
- if (pointerId == mActivePointerId) {
- // This was our active pointer going up. Choose a new
- // active pointer and adjust accordingly.
- // TODO: Make this decision more intelligent.
- final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionX = ev.getX(newPointerIndex);
- mLastMotionY = ev.getY(newPointerIndex);
- mActivePointerId = ev.getPointerId(newPointerIndex);
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
- }
- }
-
- /**
- * If one of our descendant views decides that it could be focused now, only
- * pass that along if it's on the current screen.
- *
- * This happens when live folders requery, and if they're off screen, they
- * end up calling requestFocus, which pulls it on screen.
- */
- @Override
- public void focusableViewAvailable(View focused) {
- View current = getChildAt(mCurrentScreen);
- View v = focused;
- while (true) {
- if (v == current) {
- super.focusableViewAvailable(focused);
- return;
- }
- if (v == this) {
- return;
- }
- ViewParent parent = v.getParent();
- if (parent instanceof View) {
- v = (View)v.getParent();
- } else {
- return;
- }
- }
- }
-
- void enableChildrenCache(int fromScreen, int toScreen) {
- if (fromScreen > toScreen) {
- final int temp = fromScreen;
- fromScreen = toScreen;
- toScreen = temp;
- }
-
- final int count = getChildCount();
-
- fromScreen = Math.max(fromScreen, 0);
- toScreen = Math.min(toScreen, count - 1);
-
- for (int i = fromScreen; i <= toScreen; i++) {
+ for (int i = fromPage; i <= toPage; i++) {
final CellLayout layout = (CellLayout) getChildAt(i);
layout.setChildrenDrawnWithCacheEnabled(true);
layout.setChildrenDrawingCacheEnabled(true);
@@ -819,8 +1140,8 @@
}
void clearChildrenCache() {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
+ final int screenCount = getChildCount();
+ for (int i = 0; i < screenCount; i++) {
final CellLayout layout = (CellLayout) getChildAt(i);
layout.setChildrenDrawnWithCacheEnabled(false);
}
@@ -828,316 +1149,726 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
-
if (mLauncher.isAllAppsVisible()) {
// Cancel any scrolling that is in progress.
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
- snapToScreen(mCurrentScreen);
- return false; // We don't want the events. Let them fall through to the all apps view.
+ setCurrentPage(mCurrentPage);
+
+ if (mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
+ mLauncher.showWorkspace(true);
+ // Let the events fall through to the CellLayouts because if they are not
+ // hit, then we get a crash due to a missing ACTION_DOWN touch event
+ }
+
+ return false; // We don't want the events
}
- acquireVelocityTrackerAndAddMovement(ev);
+ return super.onTouchEvent(ev);
+ }
- final int action = ev.getAction();
+ @Override
+ protected void onWallpaperTap(MotionEvent ev) {
+ final int[] position = mTempCell;
+ getLocationOnScreen(position);
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- /*
- * If being flinged and user touches, stop the fling. isFinished
- * will be false if being flinged.
- */
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
+ int pointerIndex = ev.getActionIndex();
+ position[0] += (int) ev.getX(pointerIndex);
+ position[1] += (int) ev.getY(pointerIndex);
+
+ mWallpaperManager.sendWallpaperCommand(getWindowToken(),
+ ev.getAction() == MotionEvent.ACTION_UP
+ ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,
+ position[0], position[1], 0, null);
+ }
+
+ public boolean isSmall() {
+ return mIsSmall;
+ }
+
+ private float getYScaleForScreen(int screen) {
+ int x = Math.abs(screen - 2);
+
+ // TODO: This should be generalized for use with arbitrary rotation angles.
+ switch(x) {
+ case 0: return EXTRA_SCALE_FACTOR_0;
+ case 1: return EXTRA_SCALE_FACTOR_1;
+ case 2: return EXTRA_SCALE_FACTOR_2;
+ }
+ return 1.0f;
+ }
+
+ public void shrink(ShrinkState shrinkState) {
+ shrink(shrinkState, true);
+ }
+
+ // we use this to shrink the workspace for the all apps view and the customize view
+ public void shrink(ShrinkState shrinkState, boolean animated) {
+ if (mFirstLayout) {
+ // (mFirstLayout == "first layout has not happened yet")
+ // if we get a call to shrink() as part of our initialization (for example, if
+ // Launcher is started in All Apps mode) then we need to wait for a layout call
+ // to get our width so we can layout the mini-screen views correctly
+ mWaitingToShrink = true;
+ mWaitingToShrinkState = shrinkState;
+ return;
+ }
+ // Stop any scrolling, move to the current page right away
+ setCurrentPage((mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage);
+ if (!mIsDragInProcess) {
+ updateWhichPagesAcceptDrops(shrinkState);
+ }
+
+ CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
+ if (currentPage == null) {
+ Log.w(TAG, "currentPage is NULL! mCurrentPage " + mCurrentPage
+ + " mNextPage " + mNextPage);
+ return;
+ }
+ if (currentPage.getBackgroundAlphaMultiplier() < 1.0f) {
+ currentPage.setBackgroundAlpha(0.0f);
+ }
+ currentPage.setBackgroundAlphaMultiplier(1.0f);
+
+ mIsSmall = true;
+ mShrinkState = shrinkState;
+
+ // we intercept and reject all touch events when we're small, so be sure to reset the state
+ mTouchState = TOUCH_STATE_REST;
+ mActivePointerId = INVALID_POINTER;
+
+ final Resources res = getResources();
+ final int screenWidth = getWidth();
+ final int screenHeight = getHeight();
+
+ // Making the assumption that all pages have the same width as the 0th
+ final int pageWidth = getChildAt(0).getMeasuredWidth();
+ final int pageHeight = getChildAt(0).getMeasuredHeight();
+
+ final int scaledPageWidth = (int) (SHRINK_FACTOR * pageWidth);
+ final int scaledPageHeight = (int) (SHRINK_FACTOR * pageHeight);
+ final float extraScaledSpacing = res.getDimension(R.dimen.smallScreenExtraSpacing);
+
+ final int screenCount = getChildCount();
+ float totalWidth = screenCount * scaledPageWidth + (screenCount - 1) * extraScaledSpacing;
+
+ boolean isPortrait = getMeasuredHeight() > getMeasuredWidth();
+ float newY = (isPortrait ?
+ getResources().getDimension(R.dimen.allAppsSmallScreenVerticalMarginPortrait) :
+ getResources().getDimension(R.dimen.allAppsSmallScreenVerticalMarginLandscape));
+ float finalAlpha = 1.0f;
+ float extraShrinkFactor = 1.0f;
+
+ if (shrinkState == ShrinkState.BOTTOM_VISIBLE) {
+ newY = screenHeight - newY - scaledPageHeight;
+ } else if (shrinkState == ShrinkState.BOTTOM_HIDDEN) {
+ // We shrink and disappear to nothing in the case of all apps
+ // (which is when we shrink to the bottom)
+ newY = screenHeight - newY - scaledPageHeight;
+ finalAlpha = 0.0f;
+ } else if (shrinkState == ShrinkState.MIDDLE) {
+ newY = screenHeight / 2 - scaledPageHeight / 2;
+ finalAlpha = 1.0f;
+ } else if (shrinkState == ShrinkState.TOP) {
+ newY = (isPortrait ?
+ getResources().getDimension(R.dimen.customizeSmallScreenVerticalMarginPortrait) :
+ getResources().getDimension(R.dimen.customizeSmallScreenVerticalMarginLandscape));
+ }
+
+ int duration;
+ if (shrinkState == ShrinkState.BOTTOM_HIDDEN || shrinkState == ShrinkState.BOTTOM_VISIBLE) {
+ duration = res.getInteger(R.integer.config_allAppsWorkspaceShrinkTime);
+ } else {
+ duration = res.getInteger(R.integer.config_customizeWorkspaceShrinkTime);
+ }
+
+ // We animate all the screens to the centered position in workspace
+ // At the same time, the screens become greyed/dimmed
+
+ // newX is initialized to the left-most position of the centered screens
+ float newX = mScroller.getFinalX() + screenWidth / 2 - totalWidth / 2;
+
+ // We are going to scale about the center of the view, so we need to adjust the positions
+ // of the views accordingly
+ newX -= (pageWidth - scaledPageWidth) / 2.0f;
+ newY -= (pageHeight - scaledPageHeight) / 2.0f;
+
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+
+ mAnimator = new AnimatorSet();
+ for (int i = 0; i < screenCount; i++) {
+ final CellLayout cl = (CellLayout) getChildAt(i);
+
+ float rotation = (-i + 2) * WORKSPACE_ROTATION;
+ float rotationScaleX = (float) (1.0f / Math.cos(Math.PI * rotation / 180.0f));
+ float rotationScaleY = getYScaleForScreen(i);
+
+ if (animated) {
+ ObjectAnimator animWithInterpolator = ObjectAnimator.ofPropertyValuesHolder(cl,
+ PropertyValuesHolder.ofFloat("x", newX),
+ PropertyValuesHolder.ofFloat("y", newY),
+ PropertyValuesHolder.ofFloat("scaleX",
+ SHRINK_FACTOR * rotationScaleX * extraShrinkFactor),
+ PropertyValuesHolder.ofFloat("scaleY",
+ SHRINK_FACTOR * rotationScaleY * extraShrinkFactor),
+ PropertyValuesHolder.ofFloat("backgroundAlpha", finalAlpha),
+ PropertyValuesHolder.ofFloat("alpha", finalAlpha),
+ PropertyValuesHolder.ofFloat("rotationY", rotation));
+
+ animWithInterpolator.setDuration(duration);
+ animWithInterpolator.setInterpolator(mZoomOutInterpolator);
+ mAnimator.playTogether(animWithInterpolator);
+ } else {
+ cl.setX((int)newX);
+ cl.setY((int)newY);
+ cl.setScaleX(SHRINK_FACTOR * rotationScaleX * extraShrinkFactor);
+ cl.setScaleY(SHRINK_FACTOR * rotationScaleY * extraShrinkFactor);
+ cl.setBackgroundAlpha(finalAlpha);
+ cl.setAlpha(finalAlpha);
+ cl.setRotationY(rotation);
+ mShrinkAnimationListener.onAnimationEnd(null);
+ }
+ // increment newX for the next screen
+ newX += scaledPageWidth + extraScaledSpacing;
+ }
+
+ float wallpaperOffset = 0.5f;
+ Display display = mLauncher.getWindowManager().getDefaultDisplay();
+ int wallpaperTravelHeight = (int) (display.getHeight() *
+ wallpaperTravelToScreenHeightRatio(display.getWidth(), display.getHeight()));
+ float offsetFromCenter = (wallpaperTravelHeight / (float) mWallpaperHeight) / 2f;
+ switch (shrinkState) {
+ case TOP:
+ wallpaperOffset = 0.5f + offsetFromCenter;
+ break;
+ case MIDDLE:
+ case SPRING_LOADED:
+ wallpaperOffset = 0.5f;
+ break;
+ case BOTTOM_HIDDEN:
+ case BOTTOM_VISIBLE:
+ wallpaperOffset = 0.5f - offsetFromCenter;
+ break;
+ }
+
+ setLayoutScale(1.0f);
+ if (animated) {
+ mSyncWallpaperOffsetWithScroll = false;
+ ObjectAnimator wallpaperAnim = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat("verticalWallpaperOffset", wallpaperOffset),
+ PropertyValuesHolder.ofFloat("horizontalWallpaperOffset", 0.5f));
+ mAnimator.play(wallpaperAnim);
+
+ wallpaperAnim.setDuration(duration);
+ wallpaperAnim.setInterpolator(mZoomOutInterpolator);
+ mAnimator.addListener(mShrinkAnimationListener);
+ mAnimator.start();
+ } else {
+ setVerticalWallpaperOffset(wallpaperOffset);
+ setHorizontalWallpaperOffset(0.5f);
+ updateWallpaperOffsetImmediately();
+ }
+ setChildrenDrawnWithCacheEnabled(true);
+
+ if (shrinkState == ShrinkState.TOP) {
+ showBackgroundGradientForCustomizeTray();
+ } else {
+ showBackgroundGradientForAllApps();
+ }
+ }
+
+ /*
+ * This interpolator emulates the rate at which the perceived scale of an object changes
+ * as its distance from a camera increases. When this interpolator is applied to a scale
+ * animation on a view, it evokes the sense that the object is shrinking due to moving away
+ * from the camera.
+ */
+ static class ZInterpolator implements TimeInterpolator {
+ private float focalLength;
+
+ public ZInterpolator(float foc) {
+ focalLength = foc;
+ }
+
+ public float getInterpolation(float input) {
+ return (1.0f - focalLength / (focalLength + input)) /
+ (1.0f - focalLength / (focalLength + 1.0f));
+ }
+ }
+
+ /*
+ * The exact reverse of ZInterpolator.
+ */
+ static class InverseZInterpolator implements TimeInterpolator {
+ private ZInterpolator zInterpolator;
+ public InverseZInterpolator(float foc) {
+ zInterpolator = new ZInterpolator(foc);
+ }
+ public float getInterpolation(float input) {
+ return 1 - zInterpolator.getInterpolation(1 - input);
+ }
+ }
+
+ /*
+ * ZInterpolator compounded with an ease-out.
+ */
+ static class ZoomOutInterpolator implements TimeInterpolator {
+ private final ZInterpolator zInterpolator = new ZInterpolator(0.2f);
+ private final DecelerateInterpolator decelerate = new DecelerateInterpolator(1.5f);
+
+ public float getInterpolation(float input) {
+ return decelerate.getInterpolation(zInterpolator.getInterpolation(input));
+ }
+ }
+
+ /*
+ * InvereZInterpolator compounded with an ease-out.
+ */
+ static class ZoomInInterpolator implements TimeInterpolator {
+ private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
+ private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
+
+ public float getInterpolation(float input) {
+ return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
+ }
+ }
+
+ private final ZoomOutInterpolator mZoomOutInterpolator = new ZoomOutInterpolator();
+ private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
+
+ private void updateWhichPagesAcceptDrops(ShrinkState state) {
+ updateWhichPagesAcceptDropsHelper(state, false, 1, 1);
+ }
+
+ private void updateWhichPagesAcceptDropsDuringDrag(ShrinkState state, int spanX, int spanY) {
+ updateWhichPagesAcceptDropsHelper(state, true, spanX, spanY);
+ }
+
+ private void updateWhichPagesAcceptDropsHelper(
+ ShrinkState state, boolean isDragHappening, int spanX, int spanY) {
+ final int screenCount = getChildCount();
+ 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 (!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).
+ *
+ */
+ public void onDragStartedWithItemSpans(int spanX, int spanY, Bitmap b) {
+ 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(b, canvas, bitmapPadding);
+
+ updateWhichPagesAcceptDropsDuringDrag(mShrinkState, spanX, spanY);
+ }
+
+ // we call this method whenever a drag and drop in Launcher finishes, even if Workspace was
+ // never dragged over
+ public void onDragStopped(boolean success) {
+ // In the success case, DragController has already called onDragExit()
+ if (!success) {
+ doDragExit();
+ }
+ mIsDragInProcess = false;
+ updateWhichPagesAcceptDrops(mShrinkState);
+ }
+
+ // We call this when we trigger an unshrink by clicking on the CellLayout cl
+ public void unshrink(CellLayout clThatWasClicked) {
+ unshrink(clThatWasClicked, false);
+ }
+
+ public void unshrink(CellLayout clThatWasClicked, boolean springLoaded) {
+ int newCurrentPage = indexOfChild(clThatWasClicked);
+ if (mIsSmall) {
+ if (springLoaded) {
+ setLayoutScale(SPRING_LOADED_DRAG_SHRINK_FACTOR);
+ }
+ moveToNewPageWithoutMovingCellLayouts(newCurrentPage);
+ unshrink(true, springLoaded);
+ }
+ }
+
+
+ public void enterSpringLoadedDragMode(CellLayout clThatWasClicked) {
+ mShrinkState = ShrinkState.SPRING_LOADED;
+ unshrink(clThatWasClicked, true);
+ mDragTargetLayout.onDragEnter();
+ }
+
+ public void exitSpringLoadedDragMode(ShrinkState shrinkState) {
+ shrink(shrinkState);
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragExit();
+ }
+ }
+
+ void unshrink(boolean animated) {
+ unshrink(animated, false);
+ }
+
+ void unshrink(boolean animated, boolean springLoaded) {
+ mWaitingToShrink = false;
+ if (mIsSmall) {
+ float finalScaleFactor = 1.0f;
+ float finalBackgroundAlpha = 0.0f;
+ if (springLoaded) {
+ finalScaleFactor = SPRING_LOADED_DRAG_SHRINK_FACTOR;
+ finalBackgroundAlpha = 1.0f;
+ } else {
+ mIsSmall = false;
+ }
+ if (mAnimator != null) {
+ mAnimator.cancel();
}
- // Remember where the motion event started
- mLastMotionX = ev.getX();
- mActivePointerId = ev.getPointerId(0);
- if (mTouchState == TOUCH_STATE_SCROLLING) {
- enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);
- }
- break;
- case MotionEvent.ACTION_MOVE:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
- // Scroll to follow the motion event
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
- final float x = ev.getX(pointerIndex);
- final float deltaX = mLastMotionX - x;
- mLastMotionX = x;
+ mAnimator = new AnimatorSet();
+ final int screenCount = getChildCount();
- if (deltaX < 0) {
- if (mTouchX > 0) {
- mTouchX += Math.max(-mTouchX, deltaX);
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
- invalidate();
- }
- } else if (deltaX > 0) {
- final float availableToScroll = getChildAt(getChildCount() - 1).getRight() -
- mTouchX - getWidth();
- if (availableToScroll > 0) {
- mTouchX += Math.min(availableToScroll, deltaX);
- mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
- invalidate();
- }
+ final int duration = getResources().getInteger(R.integer.config_workspaceUnshrinkTime);
+ for (int i = 0; i < screenCount; i++) {
+ final CellLayout cl = (CellLayout)getChildAt(i);
+ float finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f;
+ 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 = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
+
+ if (animated) {
+ ObjectAnimator animWithInterpolator = ObjectAnimator.ofPropertyValuesHolder(cl,
+ PropertyValuesHolder.ofFloat("translationX", translation),
+ PropertyValuesHolder.ofFloat("translationY", 0.0f),
+ PropertyValuesHolder.ofFloat("scaleX", finalScaleFactor),
+ PropertyValuesHolder.ofFloat("scaleY", finalScaleFactor),
+ PropertyValuesHolder.ofFloat("backgroundAlpha", finalBackgroundAlpha),
+ PropertyValuesHolder.ofFloat("backgroundAlphaMultiplier",
+ finalAlphaMultiplierValue),
+ PropertyValuesHolder.ofFloat("alpha", finalAlphaValue));
+ animWithInterpolator.setDuration(duration);
+ animWithInterpolator.setInterpolator(mZoomInInterpolator);
+
+ ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(cl,
+ PropertyValuesHolder.ofFloat("rotationY", rotation));
+ rotationAnim.setDuration(duration);
+ rotationAnim.setInterpolator(new DecelerateInterpolator(2.0f));
+
+ mAnimator.playTogether(animWithInterpolator, rotationAnim);
} else {
- awakenScrollBars();
+ cl.setTranslationX(translation);
+ cl.setTranslationY(0.0f);
+ cl.setScaleX(finalScaleFactor);
+ cl.setScaleY(finalScaleFactor);
+ cl.setBackgroundAlpha(0.0f);
+ cl.setBackgroundAlphaMultiplier(finalAlphaMultiplierValue);
+ cl.setAlpha(finalAlphaValue);
+ cl.setRotationY(rotation);
+ mUnshrinkAnimationListener.onAnimationEnd(null);
}
}
- break;
- case MotionEvent.ACTION_UP:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
-
- final int screenWidth = getWidth();
- final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
- final float scrolledPos = (float) mScrollX / screenWidth;
-
- if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
- // Fling hard enough to move left.
- // Don't fling across more than one screen at a time.
- final int bound = scrolledPos < whichScreen ?
- mCurrentScreen - 1 : mCurrentScreen;
- snapToScreen(Math.min(whichScreen, bound), velocityX, true);
- } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {
- // Fling hard enough to move right
- // Don't fling across more than one screen at a time.
- final int bound = scrolledPos > whichScreen ?
- mCurrentScreen + 1 : mCurrentScreen;
- snapToScreen(Math.max(whichScreen, bound), velocityX, true);
- } else {
- snapToScreen(whichScreen, 0, true);
- }
+ if (animated) {
+ ObjectAnimator wallpaperAnim = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(
+ "verticalWallpaperOffset", 0.5f),
+ PropertyValuesHolder.ofFloat(
+ "horizontalWallpaperOffset", wallpaperOffsetForCurrentScroll()));
+ mAnimator.play(wallpaperAnim);
+ wallpaperAnim.setDuration(duration);
+ wallpaperAnim.setInterpolator(mZoomInInterpolator);
+ } else {
+ setHorizontalWallpaperOffset(wallpaperOffsetForCurrentScroll());
+ setVerticalWallpaperOffset(0.5f);
+ updateWallpaperOffsetImmediately();
}
- mTouchState = TOUCH_STATE_REST;
- mActivePointerId = INVALID_POINTER;
- releaseVelocityTracker();
- break;
- case MotionEvent.ACTION_CANCEL:
- if (mTouchState == TOUCH_STATE_SCROLLING) {
- final int screenWidth = getWidth();
- final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
- snapToScreen(whichScreen, 0, true);
+
+ if (animated) {
+ // If we call this when we're not animated, onAnimationEnd is never called on
+ // the listener; make sure we only use the listener when we're actually animating
+ mAnimator.addListener(mUnshrinkAnimationListener);
+ mAnimator.start();
}
- mTouchState = TOUCH_STATE_REST;
- mActivePointerId = INVALID_POINTER;
- releaseVelocityTracker();
- break;
- case MotionEvent.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- break;
}
- return true;
- }
-
- private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) {
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
- }
-
- private void releaseVelocityTracker() {
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
+ if (!springLoaded) {
+ hideBackgroundGradient();
}
}
- void snapToScreen(int whichScreen) {
- snapToScreen(whichScreen, 0, false);
+ /**
+ * Draw the View v into the given Canvas.
+ *
+ * @param v the view to draw
+ * @param destCanvas the canvas to draw on
+ * @param padding the horizontal and vertical padding to use when drawing
+ */
+ private void drawDragView(View v, Canvas destCanvas, int padding) {
+ final Rect clipRect = mTempRect;
+ v.getDrawingRect(clipRect);
+
+ // For a TextView, adjust the clip rect so that we don't include the text label
+ if (v instanceof BubbleTextView) {
+ final BubbleTextView tv = (BubbleTextView) v;
+ clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
+ tv.getLayout().getLineTop(0);
+ } else if (v instanceof TextView) {
+ final TextView tv = (TextView) v;
+ clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() +
+ tv.getLayout().getLineTop(0);
+ }
+
+ // Draw the View into the bitmap.
+ // The translate of scrollX and scrollY is necessary when drawing TextViews, because
+ // they set scrollX and scrollY to large values to achieve centered text
+
+ destCanvas.save();
+ destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
+ destCanvas.clipRect(clipRect, Op.REPLACE);
+ v.draw(destCanvas);
+ destCanvas.restore();
}
- private void snapToScreen(int whichScreen, int velocity, boolean settle) {
- //if (!mScroller.isFinished()) return;
+ /**
+ * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
+ * Responsibility for the bitmap is transferred to the caller.
+ */
+ private Bitmap createDragOutline(View v, Canvas canvas, int padding) {
+ final int outlineColor = getResources().getColor(R.color.drag_outline_color);
+ final Bitmap b = Bitmap.createBitmap(
+ v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
- whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
-
- clearVacantCache();
- enableChildrenCache(mCurrentScreen, whichScreen);
+ canvas.setBitmap(b);
+ drawDragView(v, canvas, padding);
+ mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
+ return b;
+ }
- mNextScreen = whichScreen;
+ /**
+ * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
+ * Responsibility for the bitmap is transferred to the caller.
+ */
+ private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding) {
+ final int outlineColor = getResources().getColor(R.color.drag_outline_color);
+ final Bitmap b = Bitmap.createBitmap(
+ orig.getWidth() + padding, orig.getHeight() + padding, Bitmap.Config.ARGB_8888);
- mPreviousIndicator.setLevel(mNextScreen);
- mNextIndicator.setLevel(mNextScreen);
+ canvas.setBitmap(b);
+ canvas.drawBitmap(orig, 0, 0, new Paint());
+ mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
- View focusedChild = getFocusedChild();
- if (focusedChild != null && whichScreen != mCurrentScreen &&
- focusedChild == getChildAt(mCurrentScreen)) {
- focusedChild.clearFocus();
- }
-
- final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));
- final int newX = whichScreen * getWidth();
- final int delta = newX - mScrollX;
- int duration = (screenDelta + 1) * 100;
+ return b;
+ }
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
-
- if (settle) {
- mScrollInterpolator.setDistance(screenDelta);
- } else {
- mScrollInterpolator.disableSettle();
- }
-
- velocity = Math.abs(velocity);
- if (velocity > 0) {
- duration += (duration / (velocity / BASELINE_FLING_VELOCITY))
- * FLING_VELOCITY_INFLUENCE;
- } else {
- duration += 100;
- }
+ /**
+ * Creates a drag outline to represent a drop (that we don't have the actual information for
+ * yet). May be changed in the future to alter the drop outline slightly depending on the
+ * clip description mime data.
+ */
+ private Bitmap createExternalDragOutline(Canvas canvas, int padding) {
+ Resources r = getResources();
+ final int outlineColor = r.getColor(R.color.drag_outline_color);
+ final int iconWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
+ final int iconHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
+ final int rectRadius = r.getDimensionPixelSize(R.dimen.external_drop_icon_rect_radius);
+ final int inset = (int) (Math.min(iconWidth, iconHeight) * 0.2f);
+ final Bitmap b = Bitmap.createBitmap(
+ iconWidth + padding, iconHeight + padding, Bitmap.Config.ARGB_8888);
- awakenScrollBars(duration);
- mScroller.startScroll(mScrollX, 0, delta, 0, duration);
- invalidate();
+ canvas.setBitmap(b);
+ canvas.drawRoundRect(new RectF(inset, inset, iconWidth - inset, iconHeight - inset),
+ rectRadius, rectRadius, mExternalDragOutlinePaint);
+ mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
+ return b;
+ }
+
+ /**
+ * Returns a new bitmap to show when the given View is being dragged around.
+ * Responsibility for the bitmap is transferred to the caller.
+ */
+ private Bitmap createDragBitmap(View v, Canvas canvas, int padding) {
+ final int outlineColor = getResources().getColor(R.color.drag_outline_color);
+ final Bitmap b = Bitmap.createBitmap(
+ mDragOutline.getWidth(), mDragOutline.getHeight(), Bitmap.Config.ARGB_8888);
+
+ canvas.setBitmap(b);
+ canvas.drawBitmap(mDragOutline, 0, 0, null);
+ drawDragView(v, canvas, padding);
+ mOutlineHelper.applyOuterBlur(b, canvas, outlineColor);
+
+ return b;
}
void startDrag(CellLayout.CellInfo cellInfo) {
View child = cellInfo.cell;
-
+
// Make sure the drag was started by a long press as opposed to a long click.
if (!child.isInTouchMode()) {
return;
}
-
+
mDragInfo = cellInfo;
- mDragInfo.screen = mCurrentScreen;
-
- CellLayout current = ((CellLayout) getChildAt(mCurrentScreen));
+ CellLayout current = (CellLayout) getChildAt(cellInfo.screen);
current.onDragChild(child);
- mDragController.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
- invalidate();
+
+ child.clearFocus();
+ child.setPressed(false);
+
+ 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(child, canvas, bitmapPadding);
+
+ // The drag bitmap follows the touch point around on the screen
+ final Bitmap b = createDragBitmap(child, canvas, bitmapPadding);
+
+ 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;
+ mLauncher.lockScreenOrientation();
+ mDragController.startDrag(b, screenX, screenY, 0, 0, bmpWidth, bmpHeight, this,
+ child.getTag(), DragController.DRAG_ACTION_MOVE, null);
+ b.recycle();
}
- @Override
- protected Parcelable onSaveInstanceState() {
- final SavedState state = new SavedState(super.onSaveInstanceState());
- state.currentScreen = mCurrentScreen;
- return state;
- }
+ void addApplicationShortcut(ShortcutInfo info, int screen, int cellX, int cellY,
+ boolean insertAtFirst, int intersectX, int intersectY) {
+ final CellLayout cellLayout = (CellLayout) getChildAt(screen);
+ View view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo) info);
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- SavedState savedState = (SavedState) state;
- super.onRestoreInstanceState(savedState.getSuperState());
- if (savedState.currentScreen != -1) {
- mCurrentScreen = savedState.currentScreen;
- Launcher.setScreen(mCurrentScreen);
- }
- }
-
- void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo) {
- addApplicationShortcut(info, cellInfo, false);
- }
-
- void addApplicationShortcut(ShortcutInfo info, CellLayout.CellInfo cellInfo,
- boolean insertAtFirst) {
- final CellLayout layout = (CellLayout) getChildAt(cellInfo.screen);
- final int[] result = new int[2];
-
- layout.cellToPoint(cellInfo.cellX, cellInfo.cellY, result);
- onDropExternal(result[0], result[1], info, layout, insertAtFirst);
- }
-
- public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- final CellLayout cellLayout = getCurrentDropLayout();
- if (source != this) {
- onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout);
- } else {
- // Move internally
- if (mDragInfo != null) {
- final View cell = mDragInfo.cell;
- int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;
- if (index != mDragInfo.screen) {
- final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen);
- originalCellLayout.removeView(cell);
- cellLayout.addView(cell);
- }
- mTargetCell = estimateDropCell(x - xOffset, y - yOffset,
- mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, mTargetCell);
- cellLayout.onDropChild(cell, mTargetCell);
-
- final ItemInfo info = (ItemInfo) cell.getTag();
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
- LauncherModel.moveItemInDatabase(mLauncher, info,
- LauncherSettings.Favorites.CONTAINER_DESKTOP, index, lp.cellX, lp.cellY);
- }
- }
- }
-
- public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
- DragView dragView, Object dragInfo) {
- clearVacantCache();
- }
-
- 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) {
- clearVacantCache();
- }
-
- private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout) {
- onDropExternal(x, y, dragInfo, cellLayout, false);
- }
-
- private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout,
- boolean insertAtFirst) {
- // Drag from somewhere else
- ItemInfo info = (ItemInfo) dragInfo;
-
- View view;
-
- switch (info.itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- if (info.container == NO_ID && info instanceof ApplicationInfo) {
- // Came from all apps -- make a copy
- info = new ShortcutInfo((ApplicationInfo)info);
- }
- view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo)info);
- break;
- case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
- view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
- (ViewGroup) getChildAt(mCurrentScreen), ((UserFolderInfo) info));
- break;
- default:
- throw new IllegalStateException("Unknown item type: " + info.itemType);
- }
-
- cellLayout.addView(view, insertAtFirst ? 0 : -1);
- view.setHapticFeedbackEnabled(false);
- view.setOnLongClickListener(mLongClickListener);
- if (view instanceof DropTarget) {
- mDragController.addDropTarget((DropTarget) view);
- }
-
- mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell);
- cellLayout.onDropChild(view, mTargetCell);
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
-
+ final int[] cellXY = new int[2];
+ cellLayout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
+ addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
- LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
+ LauncherSettings.Favorites.CONTAINER_DESKTOP, screen,
+ cellXY[0], cellXY[1]);
}
-
- /**
- * Return the current {@link CellLayout}, correctly picking the destination
- * screen while a scroll is in progress.
+
+ private void setPositionForDropAnimation(
+ View dragView, int dragViewX, int dragViewY, View parent, View child) {
+ 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);
+
+ // 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);
+ }
+
+ /*
+ * We should be careful that this method cannot result in any synchronous requestLayout()
+ * calls, as it is called from onLayout().
*/
- private CellLayout getCurrentDropLayout() {
- int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen;
- return (CellLayout) getChildAt(index);
+ public void animateViewIntoPosition(final View view) {
+ final CellLayout parent = (CellLayout) view.getParent();
+ 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 dx = lp.x - lp.oldX;
+ final int dy = lp.y - lp.oldY;
+
+ // Calculate the duration of the animation based on the object's distance
+ final float dist = (float) Math.sqrt(dx*dx + dy*dy);
+ final Resources res = getResources();
+ final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
+ int duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
+ if (dist < maxDist) {
+ duration *= mQuintEaseOutInterpolator.getInterpolation(dist / maxDist);
+ }
+
+ if (mDropAnim != null) {
+ mDropAnim.end();
+ }
+ mDropAnim = new ValueAnimator();
+ mDropAnim.setInterpolator(mQuintEaseOutInterpolator);
+
+ // The view is invisible during the animation; we render it manually.
+ mDropAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationStart(Animator animation) {
+ // Set this here so that we don't render it until the animation begins
+ mDropView = view;
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ if (mDropView != null) {
+ mDropView.setVisibility(View.VISIBLE);
+ mDropView = null;
+ }
+ }
+ });
+
+ mDropAnim.setDuration(duration);
+ mDropAnim.setFloatValues(0.0f, 1.0f);
+ mDropAnim.removeAllUpdateListeners();
+ mDropAnim.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float percent = (Float) animation.getAnimatedValue();
+ // Invalidate the old position
+ invalidate(mDropViewPos[0], mDropViewPos[1],
+ mDropViewPos[0] + view.getWidth(), mDropViewPos[1] + view.getHeight());
+
+ mDropViewPos[0] = fromX + (int) (percent * dx + 0.5f);
+ mDropViewPos[1] = fromY + (int) (percent * dy + 0.5f);
+ invalidate(mDropViewPos[0], mDropViewPos[1],
+ mDropViewPos[0] + view.getWidth(), mDropViewPos[1] + view.getHeight());
+ }
+ });
+
+ mDropAnim.start();
}
/**
@@ -1145,131 +1876,791 @@
*/
public boolean acceptDrop(DragSource source, int x, int y,
int xOffset, int yOffset, DragView dragView, Object dragInfo) {
- final CellLayout layout = getCurrentDropLayout();
- final CellLayout.CellInfo cellInfo = mDragInfo;
- final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
- final int spanY = cellInfo == null ? 1 : cellInfo.spanY;
- if (mVacantCache == null) {
- final View ignoreView = cellInfo == null ? null : cellInfo.cell;
- mVacantCache = layout.findAllVacantCells(null, ignoreView);
+ // If it's an external drop (e.g. from All Apps), check if it should be accepted
+ if (source != this) {
+ // Don't accept the drop if we're not over a screen at time of drop
+ if (mDragTargetLayout == null || !mDragTargetLayout.getAcceptsDrops()) {
+ return false;
+ }
+
+ final CellLayout.CellInfo dragCellInfo = mDragInfo;
+ final int spanX = dragCellInfo == null ? 1 : dragCellInfo.spanX;
+ final int spanY = dragCellInfo == null ? 1 : dragCellInfo.spanY;
+
+ final View ignoreView = dragCellInfo == null ? null : dragCellInfo.cell;
+
+ // Don't accept the drop if there's no room for the item
+ if (!mDragTargetLayout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) {
+ mLauncher.showOutOfSpaceMessage();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+ DragView dragView, Object dragInfo) {
+
+ int originX = x - xOffset;
+ int originY = y - yOffset;
+
+ 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];
}
- return mVacantCache.findCellForSpan(mTempEstimate, spanX, spanY, false);
+ // When you drag to a particular screen, make that the new current/default screen, so any
+ // subsequent taps add items to that screen
+ int dragTargetIndex = indexOfChild(mDragTargetLayout);
+ if (mCurrentPage != dragTargetIndex && (mIsSmall || mIsInUnshrinkAnimation)) {
+ moveToNewPageWithoutMovingCellLayouts(dragTargetIndex);
+ }
+
+ if (source != this) {
+ if (!mIsSmall || mWasSpringLoadedOnDragExit) {
+ onDropExternal(originX, originY, dragInfo, mDragTargetLayout, false);
+ } else {
+ // if we drag and drop to small screens, don't pass the touch x/y coords (when we
+ // enable spring-loaded adding, however, we do want to pass the touch x/y coords)
+ onDropExternal(-1, -1, dragInfo, mDragTargetLayout, false);
+ }
+ } else if (mDragInfo != null) {
+ final View cell = mDragInfo.cell;
+ CellLayout dropTargetLayout = mDragTargetLayout;
+
+ // 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) {
+ if (mPendingScrollDirection == DragController.SCROLL_LEFT) {
+ dropTargetLayout = (CellLayout) getChildAt(mCurrentPage - 1);
+ } else if (mPendingScrollDirection == DragController.SCROLL_RIGHT) {
+ dropTargetLayout = (CellLayout) getChildAt(mCurrentPage + 1);
+ }
+ }
+
+ 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 (screen != mCurrentPage) {
+ snapToPage(screen);
+ }
+
+ if (mTargetCell != null) {
+ if (screen != mDragInfo.screen) {
+ // Reparent the view
+ ((CellLayout) getChildAt(mDragInfo.screen)).removeView(cell);
+ addInScreen(cell, screen, mTargetCell[0], mTargetCell[1],
+ mDragInfo.spanX, mDragInfo.spanY);
+ }
+
+ // update the item's position after drop
+ final ItemInfo info = (ItemInfo) cell.getTag();
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
+ dropTargetLayout.onMove(cell, mTargetCell[0], mTargetCell[1]);
+ lp.cellX = mTargetCell[0];
+ lp.cellY = mTargetCell[1];
+ cell.setId(LauncherModel.getCellLayoutChildId(-1, mDragInfo.screen,
+ mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
+
+ LauncherModel.moveItemInDatabase(mLauncher, info,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP, screen,
+ lp.cellX, lp.cellY);
+ }
+ }
+
+ final CellLayout parent = (CellLayout) cell.getParent();
+
+ // 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);
+ boolean animateDrop = !mWasSpringLoadedOnDragExit;
+ parent.onDropChild(cell, animateDrop);
+ }
}
-
- /**
- * {@inheritDoc}
- */
- public Rect estimateDropLocation(DragSource source, int x, int y,
- int xOffset, int yOffset, DragView dragView, Object dragInfo, Rect recycle) {
- final CellLayout layout = getCurrentDropLayout();
-
- final CellLayout.CellInfo cellInfo = mDragInfo;
- final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
- final int spanY = cellInfo == null ? 1 : cellInfo.spanY;
- final View ignoreView = cellInfo == null ? null : cellInfo.cell;
-
- final Rect location = recycle != null ? recycle : new Rect();
-
- // Find drop cell and convert into rectangle
- int[] dropCell = estimateDropCell(x - xOffset, y - yOffset,
- spanX, spanY, ignoreView, layout, mTempCell);
-
- if (dropCell == null) {
+
+ public void onDragEnter(DragSource source, int x, int y, int xOffset,
+ int yOffset, DragView dragView, Object dragInfo) {
+ mDragTargetLayout = null; // Reset the drag state
+
+ if (!mIsSmall) {
+ mDragTargetLayout = getCurrentDropLayout();
+ mDragTargetLayout.onDragEnter();
+ showOutlines();
+ }
+ }
+
+ public DropTarget getDropTargetDelegate(DragSource source, int x, int y,
+ int xOffset, int yOffset, DragView dragView, Object dragInfo) {
+
+ if (mIsSmall || mIsInUnshrinkAnimation) {
+ // If we're shrunken, don't let anyone drag on folders/etc that are on the mini-screens
return null;
}
-
- layout.cellToPoint(dropCell[0], dropCell[1], mTempEstimate);
- location.left = mTempEstimate[0];
- location.top = mTempEstimate[1];
-
- layout.cellToPoint(dropCell[0] + spanX, dropCell[1] + spanY, mTempEstimate);
- location.right = mTempEstimate[0];
- location.bottom = mTempEstimate[1];
-
- return location;
+ // We may need to delegate the drag to a child view. If a 1x1 item
+ // would land in a cell occupied by a DragTarget (e.g. a Folder),
+ // then drag events should be handled by that child.
+
+ ItemInfo item = (ItemInfo)dragInfo;
+ CellLayout currentLayout = getCurrentDropLayout();
+
+ int dragPointX, dragPointY;
+ if (item.spanX == 1 && item.spanY == 1) {
+ // For a 1x1, calculate the drop cell exactly as in onDragOver
+ dragPointX = x - xOffset;
+ dragPointY = y - yOffset;
+ } else {
+ // Otherwise, use the exact drag coordinates
+ dragPointX = x;
+ dragPointY = y;
+ }
+ dragPointX += mScrollX - currentLayout.getLeft();
+ dragPointY += mScrollY - currentLayout.getTop();
+
+ // If we are dragging over a cell that contains a DropTarget that will
+ // accept the drop, delegate to that DropTarget.
+ final int[] cellXY = mTempCell;
+ currentLayout.estimateDropCell(dragPointX, dragPointY, item.spanX, item.spanY, cellXY);
+ View child = currentLayout.getChildAt(cellXY[0], cellXY[1]);
+ if (child instanceof DropTarget) {
+ DropTarget target = (DropTarget)child;
+ if (target.acceptDrop(source, x, y, xOffset, yOffset, dragView, dragInfo)) {
+ return target;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Tests to see if the drop will be accepted by Launcher, and if so, includes additional data
+ * in the returned structure related to the widgets that match the drop (or a null list if it is
+ * a shortcut drop). If the drop is not accepted then a null structure is returned.
+ */
+ private Pair<Integer, List<WidgetMimeTypeHandlerData>> validateDrag(DragEvent event) {
+ final LauncherModel model = mLauncher.getModel();
+ final ClipDescription desc = event.getClipDescription();
+ final int mimeTypeCount = desc.getMimeTypeCount();
+ for (int i = 0; i < mimeTypeCount; ++i) {
+ final String mimeType = desc.getMimeType(i);
+ if (mimeType.equals(InstallShortcutReceiver.SHORTCUT_MIMETYPE)) {
+ return new Pair<Integer, List<WidgetMimeTypeHandlerData>>(i, null);
+ } else {
+ final List<WidgetMimeTypeHandlerData> widgets =
+ model.resolveWidgetsForMimeType(mContext, mimeType);
+ if (widgets.size() > 0) {
+ return new Pair<Integer, List<WidgetMimeTypeHandlerData>>(i, widgets);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Global drag and drop handler
+ */
+ @Override
+ public boolean onDragEvent(DragEvent event) {
+ final ClipDescription desc = event.getClipDescription();
+ final CellLayout layout = (CellLayout) getChildAt(mCurrentPage);
+ final int[] pos = new int[2];
+ layout.getLocationOnScreen(pos);
+ // We need to offset the drag coordinates to layout coordinate space
+ final int x = (int) event.getX() - pos[0];
+ final int y = (int) event.getY() - pos[1];
+
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_STARTED: {
+ // Validate this drag
+ Pair<Integer, List<WidgetMimeTypeHandlerData>> test = validateDrag(event);
+ if (test != null) {
+ boolean isShortcut = (test.second == null);
+ if (isShortcut) {
+ // Check if we have enough space on this screen to add a new shortcut
+ if (!layout.findCellForSpan(pos, 1, 1)) {
+ Toast.makeText(mContext, mContext.getString(R.string.out_of_space),
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ }
+ } else {
+ // Show error message if we couldn't accept any of the items
+ Toast.makeText(mContext, mContext.getString(R.string.external_drop_widget_error),
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
+ // Create the drag outline
+ // We need to add extra padding to the bitmap to make room for the glow effect
+ final Canvas canvas = new Canvas();
+ final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
+ mDragOutline = createExternalDragOutline(canvas, bitmapPadding);
+
+ // Show the current page outlines to indicate that we can accept this drop
+ showOutlines();
+ layout.setIsDragOccuring(true);
+ layout.onDragEnter();
+ layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1);
+
+ return true;
+ }
+ case DragEvent.ACTION_DRAG_LOCATION:
+ // Visualize the drop location
+ layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1);
+ return true;
+ case DragEvent.ACTION_DROP: {
+ // Try and add any shortcuts
+ final LauncherModel model = mLauncher.getModel();
+ final ClipData data = event.getClipData();
+
+ // We assume that the mime types are ordered in descending importance of
+ // representation. So we enumerate the list of mime types and alert the
+ // user if any widgets can handle the drop. Only the most preferred
+ // representation will be handled.
+ pos[0] = x;
+ pos[1] = y;
+ Pair<Integer, List<WidgetMimeTypeHandlerData>> test = validateDrag(event);
+ if (test != null) {
+ final int index = test.first;
+ final List<WidgetMimeTypeHandlerData> widgets = test.second;
+ final boolean isShortcut = (widgets == null);
+ final String mimeType = desc.getMimeType(index);
+ if (isShortcut) {
+ final Intent intent = data.getItemAt(index).getIntent();
+ Object info = model.infoFromShortcutIntent(mContext, intent, data.getIcon());
+ onDropExternal(x, y, info, layout, false);
+ } else {
+ if (widgets.size() == 1) {
+ // If there is only one item, then go ahead and add and configure
+ // that widget
+ final AppWidgetProviderInfo widgetInfo = widgets.get(0).widgetInfo;
+ final PendingAddWidgetInfo createInfo =
+ new PendingAddWidgetInfo(widgetInfo, mimeType, data);
+ mLauncher.addAppWidgetFromDrop(createInfo, mCurrentPage, pos);
+ } else {
+ // Show the widget picker dialog if there is more than one widget
+ // that can handle this data type
+ final InstallWidgetReceiver.WidgetListAdapter adapter =
+ new InstallWidgetReceiver.WidgetListAdapter(mLauncher, mimeType,
+ data, widgets, layout, mCurrentPage, pos);
+ final AlertDialog.Builder builder =
+ new AlertDialog.Builder(mContext);
+ builder.setAdapter(adapter, adapter);
+ builder.setCancelable(true);
+ builder.setTitle(mContext.getString(
+ R.string.external_drop_widget_pick_title));
+ builder.setIcon(R.drawable.ic_no_applications);
+ builder.show();
+ }
+ }
+ }
+ return true;
+ }
+ case DragEvent.ACTION_DRAG_ENDED:
+ // Hide the page outlines after the drop
+ layout.setIsDragOccuring(false);
+ layout.onDragExit();
+ hideOutlines();
+ return true;
+ }
+ return super.onDragEvent(event);
+ }
+
+ /*
+ *
+ * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
+ * coordinate space. The argument xy is modified with the return result.
+ *
+ */
+ void mapPointFromSelfToChild(View v, float[] xy) {
+ mapPointFromSelfToChild(v, xy, null);
+ }
+
+ /*
+ *
+ * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
+ * coordinate space. The argument xy is modified with the return result.
+ *
+ * if cachedInverseMatrix is not null, this method will just use that matrix instead of
+ * computing it itself; we use this to avoid redundant matrix inversions in
+ * findMatchingPageForDragOver
+ *
+ */
+ void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {
+ if (cachedInverseMatrix == null) {
+ v.getMatrix().invert(mTempInverseMatrix);
+ cachedInverseMatrix = mTempInverseMatrix;
+ }
+ xy[0] = xy[0] + mScrollX - v.getLeft();
+ xy[1] = xy[1] + mScrollY - v.getTop();
+ cachedInverseMatrix.mapPoints(xy);
+ }
+
+ /*
+ *
+ * Convert the 2D coordinate xy from this CellLayout's coordinate space to
+ * the parent View's coordinate space. The argument xy is modified with the return result.
+ *
+ */
+ void mapPointFromChildToSelf(View v, float[] xy) {
+ v.getMatrix().mapPoints(xy);
+ xy[0] -= (mScrollX - v.getLeft());
+ xy[1] -= (mScrollY - v.getTop());
+ }
+
+ 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;
+ }
+
+ /*
+ *
+ * Returns true if the passed CellLayout cl overlaps with dragView
+ *
+ */
+ boolean overlaps(CellLayout cl, DragView dragView,
+ int dragViewX, int dragViewY, Matrix cachedInverseMatrix) {
+ // Transform the coordinates of the item being dragged to the CellLayout's coordinates
+ final float[] draggedItemTopLeft = mTempDragCoordinates;
+ draggedItemTopLeft[0] = dragViewX + dragView.getScaledDragRegionXOffset();
+ draggedItemTopLeft[1] = dragViewY + dragView.getScaledDragRegionYOffset();
+ final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates;
+ draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getScaledDragRegionWidth();
+ draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getScaledDragRegionHeight();
+
+ // Transform the dragged item's top left coordinates
+ // to the CellLayout's local coordinates
+ mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix);
+ float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]);
+ float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]);
+
+ if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) {
+ // Transform the dragged item's bottom right coordinates
+ // to the CellLayout's local coordinates
+ mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix);
+ float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]);
+ float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]);
+
+ if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) {
+ float overlap = (overlapRegionRight - overlapRegionLeft) *
+ (overlapRegionBottom - overlapRegionTop);
+ if (overlap > 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /*
+ *
+ * This method returns the CellLayout that is currently being dragged to. In order to drag
+ * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second
+ * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one
+ *
+ * Return null if no CellLayout is currently being dragged over
+ *
+ */
+ private CellLayout findMatchingPageForDragOver(
+ DragView dragView, int originX, int originY, int offsetX, int offsetY) {
+ // We loop through all the screens (ie CellLayouts) and see which ones overlap
+ // with the item being dragged and then choose the one that's closest to the touch point
+ final int screenCount = getChildCount();
+ CellLayout bestMatchingScreen = null;
+ float smallestDistSoFar = Float.MAX_VALUE;
+
+ for (int i = 0; i < screenCount; i++) {
+ CellLayout cl = (CellLayout)getChildAt(i);
+
+ final float[] touchXy = mTempTouchCoordinates;
+ touchXy[0] = originX + offsetX;
+ touchXy[1] = originY + offsetY;
+
+ // Transform the touch coordinates to the CellLayout's local coordinates
+ // If the touch point is within the bounds of the cell layout, we can return immediately
+ cl.getMatrix().invert(mTempInverseMatrix);
+ mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);
+
+ if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&
+ touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {
+ return cl;
+ }
+
+ if (overlaps(cl, dragView, originX, originY, mTempInverseMatrix)) {
+ // Get the center of the cell layout in screen coordinates
+ final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;
+ cellLayoutCenter[0] = cl.getWidth()/2;
+ cellLayoutCenter[1] = cl.getHeight()/2;
+ mapPointFromChildToSelf(cl, cellLayoutCenter);
+
+ touchXy[0] = originX + offsetX;
+ touchXy[1] = originY + offsetY;
+
+ // Calculate the distance between the center of the CellLayout
+ // and the touch point
+ float dist = squaredDistance(touchXy, cellLayoutCenter);
+
+ if (dist < smallestDistSoFar) {
+ smallestDistSoFar = dist;
+ bestMatchingScreen = cl;
+ }
+ }
+ }
+ return bestMatchingScreen;
+ }
+
+ 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;
+ boolean shrunken = mIsSmall || mIsInUnshrinkAnimation;
+ if (shrunken) {
+ layout = findMatchingPageForDragOver(
+ dragView, originX, originY, xOffset, yOffset);
+
+ if (layout != mDragTargetLayout) {
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.setIsDragOverlapping(false);
+ mSpringLoadedDragController.onDragExit();
+ }
+ mDragTargetLayout = layout;
+ if (mDragTargetLayout != null && mDragTargetLayout.getAcceptsDrops()) {
+ mDragTargetLayout.setIsDragOverlapping(true);
+ mSpringLoadedDragController.onDragEnter(mDragTargetLayout);
+ }
+ }
+ } else {
+ layout = getCurrentDropLayout();
+ if (layout != mDragTargetLayout) {
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragExit();
+ }
+ layout.onDragEnter();
+ mDragTargetLayout = layout;
+ }
+ }
+ if (!shrunken || mShrinkState == ShrinkState.SPRING_LOADED) {
+ layout = getCurrentDropLayout();
+
+ final ItemInfo item = (ItemInfo)dragInfo;
+ if (dragInfo instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo;
+
+ if (widgetInfo.spanX == -1) {
+ // Calculate the grid spans needed to fit this widget
+ int[] spans = layout.rectToCell(
+ widgetInfo.minWidth, widgetInfo.minHeight, null);
+ item.spanX = spans[0];
+ item.spanY = spans[1];
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+
+ private void doDragExit() {
+ mWasSpringLoadedOnDragExit = mShrinkState == ShrinkState.SPRING_LOADED;
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragExit();
+ }
+ if (!mIsPageMoving) {
+ hideOutlines();
+ }
+ if (mShrinkState == ShrinkState.SPRING_LOADED) {
+ mLauncher.exitSpringLoadedDragMode();
+ }
+ clearAllHovers();
+ }
+
+ public void onDragExit(DragSource source, int x, int y, int xOffset,
+ int yOffset, DragView dragView, Object dragInfo) {
+ doDragExit();
+ }
+
+ @Override
+ public void getHitRect(Rect outRect) {
+ // We want the workspace to have the whole area of the display (it will find the correct
+ // cell layout to drop to in the existing drag/drop logic.
+ final Display d = mLauncher.getWindowManager().getDefaultDisplay();
+ outRect.set(0, 0, d.getWidth(), d.getHeight());
+ }
+
+ /**
+ * Add the item specified by dragInfo to the given layout.
+ * @return true if successful
+ */
+ public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {
+ if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {
+ onDropExternal(-1, -1, (ItemInfo) dragInfo, (CellLayout) layout, false);
+ return true;
+ }
+ mLauncher.showOutOfSpaceMessage();
+ return false;
+ }
+
+ /**
+ * 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
+ * come from another app altogether.
+ *
+ * NOTE: This can also be called when we are outside of a drag event, when we want
+ * to add an item to one of the workspace screens.
+ */
+ private void onDropExternal(int x, int y, Object dragInfo,
+ CellLayout cellLayout, boolean insertAtFirst) {
+ int screen = indexOfChild(cellLayout);
+ if (dragInfo instanceof PendingAddItemInfo) {
+ PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
+ // When dragging and dropping from customization tray, we deal with creating
+ // widgets/shortcuts/folders in a slightly different way
+ // Only set touchXY if you are supporting spring loaded adding of items
+ int[] touchXY = new int[2];
+ touchXY[0] = x;
+ touchXY[1] = y;
+ switch (info.itemType) {
+ 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;
+ default:
+ throw new IllegalStateException("Unknown item type: " + info.itemType);
+ }
+ cellLayout.onDragExit();
+ } else {
+ // This is for other drag/drop cases, like dragging from All Apps
+ ItemInfo info = (ItemInfo) dragInfo;
+ View view = null;
+
+ switch (info.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ if (info.container == NO_ID && info instanceof ApplicationInfo) {
+ // Came from all apps -- make a copy
+ info = new ShortcutInfo((ApplicationInfo) info);
+ }
+ view = mLauncher.createShortcut(R.layout.application, cellLayout,
+ (ShortcutInfo) info);
+ break;
+ case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+ view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
+ cellLayout, (UserFolderInfo) info, mIconCache);
+ break;
+ default:
+ throw new IllegalStateException("Unknown item type: " + info.itemType);
+ }
+
+ mTargetCell = new int[2];
+ if (x != -1 && y != -1) {
+ // when dragging and dropping, just find the closest free spot
+ cellLayout.findNearestVacantArea(x, y, 1, 1, mTargetCell);
+ } else {
+ cellLayout.findCellForSpan(mTargetCell, 1, 1);
+ }
+ addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
+ mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
+ boolean animateDrop = !mWasSpringLoadedOnDragExit;
+ cellLayout.onDropChild(view, animateDrop);
+ cellLayout.animateDrop();
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
+
+ LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP, screen,
+ lp.cellX, lp.cellY);
+ }
+ }
+
+ /**
+ * Return the current {@link CellLayout}, correctly picking the destination
+ * screen while a scroll is in progress.
+ */
+ private CellLayout getCurrentDropLayout() {
+ // if we're currently small, use findMatchingPageForDragOver instead
+ if (mIsSmall) return null;
+ int index = mScroller.isFinished() ? mCurrentPage : mNextPage;
+ return (CellLayout) getChildAt(index);
+ }
+
+ /**
+ * Return the current CellInfo describing our current drag; this method exists
+ * so that Launcher can sync this object with the correct info when the activity is created/
+ * destroyed
+ *
+ */
+ public CellLayout.CellInfo getDragInfo() {
+ return mDragInfo;
}
/**
* Calculate the nearest cell where the given object would be dropped.
*/
- private int[] estimateDropCell(int pixelX, int pixelY,
+ private int[] findNearestVacantArea(int pixelX, int pixelY,
int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) {
- // Create vacant cell cache if none exists
- if (mVacantCache == null) {
- mVacantCache = layout.findAllVacantCells(null, ignoreView);
- }
+
+ int localPixelX = pixelX - (layout.getLeft() - mScrollX);
+ int localPixelY = pixelY - (layout.getTop() - mScrollY);
// Find the best target drop location
- return layout.findNearestVacantArea(pixelX, pixelY,
- spanX, spanY, mVacantCache, recycle);
+ return layout.findNearestVacantArea(
+ localPixelX, localPixelY, spanX, spanY, ignoreView, recycle);
}
-
+
void setLauncher(Launcher launcher) {
mLauncher = launcher;
+ mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);
+
+ mCustomizationDrawer = mLauncher.findViewById(R.id.customization_drawer);
+ if (mCustomizationDrawer != null) {
+ mCustomizationDrawerContent =
+ mCustomizationDrawer.findViewById(com.android.internal.R.id.tabcontent);
+ }
}
public void setDragController(DragController dragController) {
mDragController = dragController;
}
+ /**
+ * Called at the end of a drag which originated on the workspace.
+ */
public void onDropCompleted(View target, boolean success) {
- clearVacantCache();
-
- if (success){
+ if (success) {
if (target != this && mDragInfo != null) {
final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
cellLayout.removeView(mDragInfo.cell);
if (mDragInfo.cell instanceof DropTarget) {
mDragController.removeDropTarget((DropTarget)mDragInfo.cell);
}
- //final Object tag = mDragInfo.cell.getTag();
+ // final Object tag = mDragInfo.cell.getTag();
}
- } else {
- if (mDragInfo != null) {
- final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
- cellLayout.onDropAborted(mDragInfo.cell);
- }
+ } else if (mDragInfo != null) {
+ // NOTE: When 'success' is true, onDragExit is called by the DragController before
+ // calling onDropCompleted(). We call it ourselves here, but maybe this should be
+ // moved into DragController.cancelDrag().
+ doDragExit();
+ ((CellLayout) getChildAt(mDragInfo.screen)).onDropChild(mDragInfo.cell, false);
}
-
+ mLauncher.unlockScreenOrientation();
+ mDragOutline = null;
mDragInfo = null;
}
+ @Override
+ public void onDragViewVisible() {
+ ((View) mDragInfo.cell).setVisibility(View.GONE);
+ }
+
+ public boolean isDropEnabled() {
+ return true;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ super.onRestoreInstanceState(state);
+ Launcher.setScreen(mCurrentPage);
+ }
+
+ @Override
public void scrollLeft() {
- clearVacantCache();
- if (mScroller.isFinished()) {
- if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);
- } else {
- if (mNextScreen > 0) snapToScreen(mNextScreen - 1);
+ if (!mIsSmall && !mIsInUnshrinkAnimation) {
+ super.scrollLeft();
}
}
+ @Override
public void scrollRight() {
- clearVacantCache();
- if (mScroller.isFinished()) {
- if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);
- } else {
- if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);
+ if (!mIsSmall && !mIsInUnshrinkAnimation) {
+ super.scrollRight();
}
}
- public int getScreenForView(View v) {
- int result = -1;
- if (v != null) {
- ViewParent vp = v.getParent();
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- if (vp == getChildAt(i)) {
- return i;
+ @Override
+ public void onEnterScrollArea(int direction) {
+ if (!mIsSmall && !mIsInUnshrinkAnimation) {
+ mInScrollArea = true;
+ mPendingScrollDirection = direction;
+
+ final int page = mCurrentPage + (direction == DragController.SCROLL_LEFT ? -1 : 1);
+ final CellLayout layout = (CellLayout) getChildAt(page);
+
+ if (layout != null) {
+ layout.setIsDragOverlapping(true);
+
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragExit();
+ mDragTargetLayout = null;
}
}
}
- return result;
+ }
+
+ private void clearAllHovers() {
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ ((CellLayout) getChildAt(i)).setIsDragOverlapping(false);
+ }
+ mSpringLoadedDragController.onDragExit();
+ }
+
+ @Override
+ public void onExitScrollArea() {
+ if (mInScrollArea) {
+ mInScrollArea = false;
+ mPendingScrollDirection = DragController.SCROLL_NONE;
+ clearAllHovers();
+ }
}
public Folder getFolderForTag(Object tag) {
- int screenCount = getChildCount();
+ final int screenCount = getChildCount();
for (int screen = 0; screen < screenCount; screen++) {
CellLayout currentScreen = ((CellLayout) getChildAt(screen));
int count = currentScreen.getChildCount();
@@ -1278,7 +2669,7 @@
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) {
Folder f = (Folder) child;
- if (f.getInfo() == tag) {
+ if (f.getInfo() == tag && f.getInfo().opened) {
return f;
}
}
@@ -1302,23 +2693,9 @@
return null;
}
- /**
- * @return True is long presses are still allowed for the current touch
- */
- public boolean allowLongPress() {
- return mAllowLongPress;
- }
-
- /**
- * Set true to allow long-press events to be triggered, usually checked by
- * {@link Launcher} to accept or block dpad-initiated long-presses.
- */
- public void setAllowLongPress(boolean allowLongPress) {
- mAllowLongPress = allowLongPress;
- }
void removeItems(final ArrayList<ApplicationInfo> apps) {
- final int count = getChildCount();
+ final int screenCount = getChildCount();
final PackageManager manager = getContext().getPackageManager();
final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext());
@@ -1328,7 +2705,7 @@
packageNames.add(apps.get(i).componentName.getPackageName());
}
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < screenCount; i++) {
final CellLayout layout = (CellLayout) getChildAt(i);
// Avoid ANRs by treating each screen separately
@@ -1336,17 +2713,17 @@
public void run() {
final ArrayList<View> childrenToRemove = new ArrayList<View>();
childrenToRemove.clear();
-
+
int childCount = layout.getChildCount();
for (int j = 0; j < childCount; j++) {
final View view = layout.getChildAt(j);
Object tag = view.getTag();
-
+
if (tag instanceof ShortcutInfo) {
final ShortcutInfo info = (ShortcutInfo) tag;
final Intent intent = info.intent;
final ComponentName name = intent.getComponent();
-
+
if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
for (String packageName: packageNames) {
if (packageName.equals(name.getPackageName())) {
@@ -1361,12 +2738,12 @@
final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1);
final int contentsCount = contents.size();
boolean removedFromFolder = false;
-
+
for (int k = 0; k < contentsCount; k++) {
final ShortcutInfo appInfo = contents.get(k);
final Intent intent = appInfo.intent;
final ComponentName name = intent.getComponent();
-
+
if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
for (String packageName: packageNames) {
if (packageName.equals(name.getPackageName())) {
@@ -1377,11 +2754,12 @@
}
}
}
-
+
contents.removeAll(toRemove);
if (removedFromFolder) {
final Folder folder = getOpenFolder();
- if (folder != null) folder.notifyDataSetChanged();
+ if (folder != null)
+ folder.notifyDataSetChanged();
}
} else if (tag instanceof LiveFolderInfo) {
final LiveFolderInfo info = (LiveFolderInfo) tag;
@@ -1393,7 +2771,7 @@
for (String packageName: packageNames) {
if (packageName.equals(providerInfo.packageName)) {
LauncherModel.deleteItemFromDatabase(mLauncher, info);
- childrenToRemove.add(view);
+ childrenToRemove.add(view);
}
}
}
@@ -1405,13 +2783,13 @@
for (String packageName: packageNames) {
if (packageName.equals(provider.provider.getPackageName())) {
LauncherModel.deleteItemFromDatabase(mLauncher, info);
- childrenToRemove.add(view);
+ childrenToRemove.add(view);
}
}
}
}
}
-
+
childCount = childrenToRemove.size();
for (int j = 0; j < childCount; j++) {
View child = childrenToRemove.get(j);
@@ -1420,7 +2798,7 @@
mDragController.removeDropTarget((DropTarget)child);
}
}
-
+
if (childCount > 0) {
layout.requestLayout();
layout.invalidate();
@@ -1431,10 +2809,8 @@
}
void updateShortcuts(ArrayList<ApplicationInfo> apps) {
- final PackageManager pm = mLauncher.getPackageManager();
-
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
+ final int screenCount = getChildCount();
+ for (int i = 0; i < screenCount; i++) {
final CellLayout layout = (CellLayout) getChildAt(i);
int childCount = layout.getChildCount();
for (int j = 0; j < childCount; j++) {
@@ -1450,7 +2826,7 @@
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
final int appCount = apps.size();
- for (int k=0; k<appCount; k++) {
+ for (int k = 0; k < appCount; k++) {
ApplicationInfo app = apps.get(k);
if (app.componentName.equals(name)) {
info.setIcon(mIconCache.getIcon(info.intent));
@@ -1466,48 +2842,29 @@
}
void moveToDefaultScreen(boolean animate) {
- if (animate) {
- snapToScreen(mDefaultScreen);
+ if (mIsSmall || mIsInUnshrinkAnimation) {
+ mLauncher.showWorkspace(animate, (CellLayout)getChildAt(mDefaultPage));
+ } else if (animate) {
+ snapToPage(mDefaultPage);
} else {
- setCurrentScreen(mDefaultScreen);
+ setCurrentPage(mDefaultPage);
}
- getChildAt(mDefaultScreen).requestFocus();
+ getChildAt(mDefaultPage).requestFocus();
}
void setIndicators(Drawable previous, Drawable next) {
mPreviousIndicator = previous;
mNextIndicator = next;
- previous.setLevel(mCurrentScreen);
- next.setLevel(mCurrentScreen);
+ previous.setLevel(mCurrentPage);
+ next.setLevel(mCurrentPage);
}
- public static class SavedState extends BaseSavedState {
- int currentScreen = -1;
-
- SavedState(Parcelable superState) {
- super(superState);
- }
-
- private SavedState(Parcel in) {
- super(in);
- currentScreen = in.readInt();
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- super.writeToParcel(out, flags);
- out.writeInt(currentScreen);
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Parcelable.Creator<SavedState>() {
- public SavedState createFromParcel(Parcel in) {
- return new SavedState(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
+ @Override
+ public void syncPages() {
}
+
+ @Override
+ public void syncPageItems(int page) {
+ }
+
}
diff --git a/src/com/android/launcher2/allapps.rs b/src/com/android/launcher2/allapps.rs
new file mode 100644
index 0000000..bebc04d
--- /dev/null
+++ b/src/com/android/launcher2/allapps.rs
@@ -0,0 +1,385 @@
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.launcher2)
+
+#include "rs_graphics.rsh"
+
+#define PI 3.14159f
+
+// Constants from Java
+int COLUMNS_PER_PAGE_PORTRAIT;
+int ROWS_PER_PAGE_PORTRAIT;
+int COLUMNS_PER_PAGE_LANDSCAPE;
+int ROWS_PER_PAGE_LANDSCAPE;
+
+int gIconCount;
+int gSelectedIconIndex = -1;
+rs_allocation gSelectedIconTexture;
+rs_allocation gHomeButton;
+
+rs_program_fragment gPFTexNearest;
+rs_program_fragment gPFTexMip;
+rs_program_fragment gPFTexMipAlpha;
+rs_program_vertex gPVCurve;
+rs_program_store gPS;
+rs_mesh gSMCell;
+
+rs_allocation *gIcons;
+rs_allocation *gLabels;
+
+typedef struct VpConsts {
+ rs_matrix4x4 Proj;
+ float4 Position;
+ float4 ScaleOffset;
+ float2 BendPos;
+ float2 ImgSize;
+} VpConsts_t;
+VpConsts_t *vpConstants;
+
+// Attraction to center values from page edge to page center.
+static float g_AttractionTable[9] = {20.f, 20.f, 20.f, 10.f, -10.f, -20.f, -20.f, -20.f, -20.f};
+static float g_FrictionTable[9] = {10.f, 10.f, 11.f, 15.f, 15.f, 11.f, 10.f, 10.f, 10.f};
+static float g_PhysicsTableSize = 7;
+
+static float gZoomTarget;
+float gTargetPos;
+static float g_PosPage = 0.f;
+static float g_PosVelocity = 0.f;
+static float g_LastPositionX = 0.f;
+static bool g_LastTouchDown = false;
+static float g_DT;
+static int g_PosMax;
+static float g_Zoom = 0.f;
+static float g_Animation = 1.f;
+static float g_OldPosPage;
+static float g_OldPosVelocity;
+static float g_OldZoom;
+static float g_MoveToTotalTime = 0.2f;
+static float g_MoveToTime = 0.f;
+static float g_MoveToOldPos = 0.f;
+
+static int g_Cols;
+static int g_Rows;
+
+rs_allocation g_VPConstAlloc;
+
+// Drawing constants, should be parameters ======
+#define VIEW_ANGLE 1.28700222f
+
+
+static void updateReadback() {
+ if ((g_OldPosPage != g_PosPage) ||
+ (g_OldPosVelocity != g_PosVelocity) ||
+ (g_OldZoom != g_Zoom)) {
+
+ g_OldPosPage = g_PosPage;
+ g_OldPosVelocity = g_PosVelocity;
+ g_OldZoom = g_Zoom;
+
+ int i[3];
+ i[0] = g_PosPage * (1 << 16);
+ i[1] = g_PosVelocity * (1 << 16);
+ i[2] = g_OldZoom * (1 << 16);
+ rsSendToClientBlocking(1, &i[0], sizeof(i));
+ }
+}
+
+void init() {
+}
+
+void move(float newPos) {
+ if (g_LastTouchDown) {
+ float dx = -(newPos - g_LastPositionX);
+ g_PosVelocity = 0;
+ g_PosPage += dx * 5.2f;
+
+ float pmin = -0.49f;
+ float pmax = g_PosMax + 0.49f;
+ g_PosPage = clamp(g_PosPage, pmin, pmax);
+ }
+ g_LastTouchDown = true;
+ g_LastPositionX = newPos;
+ g_MoveToTime = 0;
+}
+
+void moveTo(float targetPos) {
+ gTargetPos = targetPos;
+ g_MoveToTime = g_MoveToTotalTime;
+ g_PosVelocity = 0;
+ g_MoveToOldPos = g_PosPage;
+}
+
+void setZoom(float z, /*bool*/ int animate) {
+ gZoomTarget = z;
+ if (gZoomTarget < 0.001f) {
+ gZoomTarget = 0;
+ }
+ if (!animate) {
+ g_Zoom = gZoomTarget;
+ }
+ updateReadback();
+}
+
+void fling(float newPos, float vel) {
+ move(newPos);
+
+ g_LastTouchDown = false;
+ g_PosVelocity = -vel * 4;
+ float av = fabs(g_PosVelocity);
+ float minVel = 3.5f;
+
+ minVel *= 1.f - (fabs(rsFrac(g_PosPage + 0.5f) - 0.5f) * 0.45f);
+
+ if (av < minVel && av > 0.2f) {
+ if (g_PosVelocity > 0) {
+ g_PosVelocity = minVel;
+ } else {
+ g_PosVelocity = -minVel;
+ }
+ }
+
+ if (g_PosPage <= 0) {
+ g_PosVelocity = max(0.f, g_PosVelocity);
+ }
+ if (g_PosPage > g_PosMax) {
+ g_PosVelocity = min(0.f, g_PosVelocity);
+ }
+}
+
+// Interpolates values in the range 0..1 to a curve that eases in
+// and out.
+static float getInterpolation(float input) {
+ return (cos((input + 1) * PI) * 0.5f) + 0.5f;
+}
+
+
+static void updatePos() {
+ if (g_LastTouchDown) {
+ return;
+ }
+
+ float tablePosNorm = rsFrac(g_PosPage + 0.5f);
+ float tablePosF = tablePosNorm * g_PhysicsTableSize;
+ int tablePosI = tablePosF;
+ float tablePosFrac = tablePosF - tablePosI;
+ float accel = mix(g_AttractionTable[tablePosI],
+ g_AttractionTable[tablePosI + 1],
+ tablePosFrac) * g_DT;
+ float friction = mix(g_FrictionTable[tablePosI],
+ g_FrictionTable[tablePosI + 1],
+ tablePosFrac) * g_DT;
+
+ if (g_MoveToTime) {
+ // New position is old posiition + (total distance) * (interpolated time)
+ g_PosPage = g_MoveToOldPos + (gTargetPos - g_MoveToOldPos) * getInterpolation((g_MoveToTotalTime - g_MoveToTime) / g_MoveToTotalTime);
+ g_MoveToTime -= g_DT;
+ if (g_MoveToTime <= 0) {
+ g_MoveToTime = 0;
+ g_PosPage = gTargetPos;
+ }
+ return;
+ }
+
+ // If our velocity is low OR acceleration is opposing it, apply it.
+ if (fabs(g_PosVelocity) < 4.0f || (g_PosVelocity * accel) < 0) {
+ g_PosVelocity += accel;
+ }
+ //RS_DEBUG(g_PosPage);
+ //RS_DEBUG(g_PosVelocity);
+ //RS_DEBUG(friction);
+ //RS_DEBUG(accel);
+
+ // Normal physics
+ if (g_PosVelocity > 0) {
+ g_PosVelocity -= friction;
+ g_PosVelocity = max(g_PosVelocity, 0.f);
+ } else {
+ g_PosVelocity += friction;
+ g_PosVelocity = min(g_PosVelocity, 0.f);
+ }
+
+ if ((friction > fabs(g_PosVelocity)) && (friction > fabs(accel))) {
+ // Special get back to center and overcome friction physics.
+ float t = tablePosNorm - 0.5f;
+ if (fabs(t) < (friction * g_DT)) {
+ // really close, just snap
+ g_PosPage = round(g_PosPage);
+ g_PosVelocity = 0;
+ } else {
+ if (t > 0) {
+ g_PosVelocity = -friction;
+ } else {
+ g_PosVelocity = friction;
+ }
+ }
+ }
+
+ // Check for out of boundry conditions.
+ if (g_PosPage < 0 && g_PosVelocity < 0) {
+ float damp = 1.0f + (g_PosPage * 4);
+ damp = clamp(damp, 0.f, 0.9f);
+ g_PosVelocity *= damp;
+ }
+ if (g_PosPage > g_PosMax && g_PosVelocity > 0) {
+ float damp = 1.0f - ((g_PosPage - g_PosMax) * 4);
+ damp = clamp(damp, 0.f, 0.9f);
+ g_PosVelocity *= damp;
+ }
+
+ g_PosPage += g_PosVelocity * g_DT;
+ g_PosPage = clamp(g_PosPage, -0.49f, g_PosMax + 0.49f);
+}
+
+static void
+draw_home_button()
+{
+ rsgBindTexture(gPFTexNearest, 0, gHomeButton);
+
+ float w = rsgGetWidth();
+ float h = rsgGetHeight();
+ float tw = rsAllocationGetDimX(gHomeButton);
+ float th = rsAllocationGetDimY(gHomeButton);
+
+ float x;
+ float y;
+ if (w > h) {
+ x = w - (tw * (1 - g_Animation)) + 20;
+ y = (h - th) * 0.5f;
+ } else {
+ x = (w - tw) / 2;
+ y = -g_Animation * th;
+ y -= 30; // move the house to the edge of the screen as it doesn't fill the texture.
+ }
+
+ rsgDrawSpriteScreenspace(x, y, 0, tw, th);
+}
+
+static void drawFrontGrid(float rowOffset, float p)
+{
+ float h = rsgGetHeight();
+ float w = rsgGetWidth();
+
+ int intRowOffset = rowOffset;
+ float rowFrac = rowOffset - intRowOffset;
+ float colWidth = 120.f;//w / 4;
+ float rowHeight = colWidth + 25.f;
+ float yoff = 0.5f * h + 1.5f * rowHeight;
+
+ int row, col;
+ int colCount = 4;
+ if (w > h) {
+ colCount = 6;
+ rowHeight -= 12.f;
+ yoff = 0.47f * h + 1.0f * rowHeight;
+ }
+
+ int iconNum = (intRowOffset - 5) * colCount;
+
+ rsgBindProgramVertex(gPVCurve);
+
+ vpConstants->Position.z = p;
+
+ for (row = -5; row < 15; row++) {
+ float y = yoff - ((-rowFrac + row) * rowHeight);
+
+ for (col=0; col < colCount; col++) {
+ if (iconNum >= gIconCount) {
+ return;
+ }
+
+ if (iconNum >= 0) {
+ float x = colWidth * col + (colWidth / 2);
+ vpConstants->Position.x = x + 0.2f;
+
+ if (gSelectedIconIndex == iconNum && !p && rsIsObject(gSelectedIconTexture)) {
+ rsgBindProgramFragment(gPFTexNearest);
+ rsgBindTexture(gPFTexNearest, 0, gSelectedIconTexture);
+ vpConstants->ImgSize.x = rsAllocationGetDimX(gSelectedIconTexture);
+ vpConstants->ImgSize.y = rsAllocationGetDimY(gSelectedIconTexture);
+ vpConstants->Position.y = y - (rsAllocationGetDimY(gSelectedIconTexture)
+ - rsAllocationGetDimY(gIcons[iconNum])) * 0.5f;
+ rsAllocationMarkDirty(g_VPConstAlloc);
+ rsgDrawMesh(gSMCell);
+ }
+
+ rsgBindProgramFragment(gPFTexMip);
+ vpConstants->ImgSize.x = rsAllocationGetDimX(gIcons[iconNum]);
+ vpConstants->ImgSize.y = rsAllocationGetDimY(gIcons[iconNum]);
+ vpConstants->Position.y = y - 0.2f;
+ rsAllocationMarkDirty(g_VPConstAlloc);
+ rsgBindTexture(gPFTexMip, 0, gIcons[iconNum]);
+ rsgDrawMesh(gSMCell);
+
+ rsgBindProgramFragment(gPFTexMipAlpha);
+ vpConstants->ImgSize.x = rsAllocationGetDimX(gLabels[iconNum]);
+ vpConstants->ImgSize.y = rsAllocationGetDimY(gLabels[iconNum]);
+ vpConstants->Position.y = y - 64.f - 0.2f;
+ rsAllocationMarkDirty(g_VPConstAlloc);
+ rsgBindTexture(gPFTexMipAlpha, 0, gLabels[iconNum]);
+ rsgDrawMesh(gSMCell);
+ }
+ iconNum++;
+ }
+ }
+}
+
+
+int root()
+{
+ // Compute dt in seconds.
+ // physics may break if DT is large.
+ g_DT = min(rsGetDt(), 0.1f);
+ g_VPConstAlloc = rsGetAllocation(vpConstants);
+
+ if (g_Zoom != gZoomTarget) {
+ float dz = g_DT * 1.7f;
+ if (gZoomTarget < 0.5f) {
+ dz = -dz;
+ }
+ if (fabs(g_Zoom - gZoomTarget) < fabs(dz)) {
+ g_Zoom = gZoomTarget;
+ } else {
+ g_Zoom += dz;
+ }
+ updateReadback();
+ }
+ g_Animation = pow(1.f - g_Zoom, 3.f);
+
+ // Set clear value to dim the background based on the zoom position.
+ if ((g_Zoom < 0.001f) && (gZoomTarget < 0.001f)) {
+ rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ // When we're zoomed out and not tracking motion events, reset the pos to 0.
+ if (!g_LastTouchDown) {
+ g_PosPage = 0;
+ }
+ return 0;
+ } else {
+ rsgClearColor(0.0f, 0.0f, 0.0f, g_Zoom);
+ }
+
+ rsgBindProgramStore(gPS);
+
+ // icons & labels
+ if (rsgGetWidth() > rsgGetHeight()) {
+ g_Cols = COLUMNS_PER_PAGE_LANDSCAPE;
+ g_Rows = ROWS_PER_PAGE_LANDSCAPE;
+ } else {
+ g_Cols = COLUMNS_PER_PAGE_PORTRAIT;
+ g_Rows = ROWS_PER_PAGE_PORTRAIT;
+ }
+
+ g_PosMax = ((gIconCount + (g_Cols-1)) / g_Cols) - g_Rows;
+ if (g_PosMax < 0) g_PosMax = 0;
+
+ updatePos();
+ updateReadback();
+
+ // Draw the icons ========================================
+ drawFrontGrid(g_PosPage, g_Animation);
+
+ rsgBindProgramFragment(gPFTexNearest);
+ draw_home_button();
+ return (g_PosVelocity != 0) || rsFrac(g_PosPage) || g_Zoom != gZoomTarget || (g_MoveToTime != 0);
+}
+
+