diff options
48 files changed, 755 insertions, 592 deletions
diff --git a/Android.mk b/Android.mk index abcca40c9..8a3d27653 100644 --- a/Android.mk +++ b/Android.mk @@ -22,7 +22,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_STATIC_JAVA_LIBRARIES := android-common android-support-v13 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - +LOCAL_SDK_VERSION := 16 LOCAL_PACKAGE_NAME := Launcher2 LOCAL_CERTIFICATE := shared diff --git a/AndroidManifest.xml b/AndroidManifest.xml index dbeb7bce1..de4a4340a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -65,7 +65,7 @@ android:name="com.android.launcher2.LauncherApplication" android:label="@string/application_name" android:icon="@drawable/ic_launcher_home" - android:hardwareAccelerated="@bool/config_hardwareAccelerated" + android:hardwareAccelerated="true" android:largeHeap="@bool/config_largeHeap"> <activity android:name="com.android.launcher2.Launcher" diff --git a/res/drawable-hdpi/default_widget_preview_holo.9.png b/res/drawable-hdpi/default_widget_preview_holo.9.png Binary files differdeleted file mode 100644 index 0b4a6343f..000000000 --- a/res/drawable-hdpi/default_widget_preview_holo.9.png +++ /dev/null diff --git a/res/drawable-mdpi/default_widget_preview_holo.9.png b/res/drawable-mdpi/default_widget_preview_holo.9.png Binary files differdeleted file mode 100644 index 0bfdaef58..000000000 --- a/res/drawable-mdpi/default_widget_preview_holo.9.png +++ /dev/null diff --git a/res/drawable-xhdpi/default_widget_preview_holo.9.png b/res/drawable-xhdpi/default_widget_preview_holo.9.png Binary files differdeleted file mode 100644 index 42d57d843..000000000 --- a/res/drawable-xhdpi/default_widget_preview_holo.9.png +++ /dev/null diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 0b01e4272..8df155e5c 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -43,7 +43,7 @@ <string name="group_wallpapers" msgid="1568191644272224858">"Hintergründe"</string> <string name="completely_out_of_space" msgid="1759078539443491182">"Auf Ihrem Startbildschirm ist kein Platz mehr vorhanden."</string> <string name="out_of_space" msgid="8365249326091984698">"Auf dem Startbildschirm ist kein Platz mehr vorhanden."</string> - <string name="hotseat_out_of_space" msgid="6304886797358479361">"Auf der App-Leiste ist kein Platz mehr vorhanden."</string> + <string name="hotseat_out_of_space" msgid="6304886797358479361">"Kein Platz mehr auf der App-Leiste"</string> <string name="invalid_hotseat_item" msgid="6545340627805449250">"Dieses Widget ist zu groß für die App-Leiste."</string> <string name="shortcut_installed" msgid="7071557296331322355">"\"<xliff:g id="NAME">%s</xliff:g>\"-Verknüpfung wurde erstellt."</string> <string name="shortcut_uninstalled" msgid="2129499669449749995">"\"<xliff:g id="NAME">%s</xliff:g>\"-Verknüpfung wurde entfernt."</string> diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index d03e82a09..9f48ef2bf 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -20,29 +20,29 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="application_name" msgid="8424725141379931883">"راه انداز"</string> - <string name="home" msgid="5921706419368316758">"صفحه اصلی"</string> - <string name="uid_name" msgid="3371120195364560632">"برنامه های Android Core"</string> + <string name="home" msgid="5921706419368316758">"صفحهٔ اصلی"</string> + <string name="uid_name" msgid="3371120195364560632">"برنامههای Android Core"</string> <string name="folder_name" msgid="8551881338202938211"></string> <string name="chooser_wallpaper" msgid="6063168087625352235">"انتخاب تصویر زمینه از"</string> <string name="wallpaper_instructions" msgid="4215640646180727542">"تنظیم تصویر زمینه"</string> <string name="pick_wallpaper" msgid="5630222540525626723">"تصاویر زمینه"</string> <string name="activity_not_found" msgid="217823393239365967">"برنامه نصب نشده است."</string> - <string name="widgets_tab_label" msgid="9145860100000983599">"ابزارک ها"</string> + <string name="widgets_tab_label" msgid="9145860100000983599">"ابزارکها"</string> <string name="long_press_widget_to_add" msgid="7395697462851217506">"برای انتخاب یک ابزارک لمس کنید و نگه دارید."</string> <string name="market" msgid="2652226429823445833">"فروشگاه"</string> - <string name="external_drop_widget_error" msgid="2285187188524172774">"این مورد را نمیتوان در این صفحه اصلی رها کرد."</string> + <string name="external_drop_widget_error" msgid="2285187188524172774">"این مورد را نمیتوان در این صفحهٔ اصلی رها کرد."</string> <string name="external_drop_widget_pick_title" msgid="7040647073452295370">"انتخاب ابزارک برای ایجاد"</string> <string name="rename_folder_label" msgid="5646236631298452787">"نام پوشه"</string> <string name="rename_folder_title" msgid="4544573104191526550">"تغییر نام پوشه"</string> <string name="rename_action" msgid="6016003384693240896">"تأیید"</string> <string name="cancel_action" msgid="3811860427489435048">"لغو"</string> - <string name="menu_item_add_item" msgid="6233177331075781114">"افزودن به صفحه اصلی"</string> + <string name="menu_item_add_item" msgid="6233177331075781114">"افزودن به صفحهٔ اصلی"</string> <string name="group_applications" msgid="2103752818818161976">"برنامهها"</string> <string name="group_shortcuts" msgid="9133529424900391877">"میانبرها"</string> - <string name="group_widgets" msgid="6704978494073105844">"ابزارک ها"</string> + <string name="group_widgets" msgid="6704978494073105844">"ابزارکها"</string> <string name="group_wallpapers" msgid="1568191644272224858">"تصاویر زمینه"</string> <string name="completely_out_of_space" msgid="1759078539443491182">"فضای بیشتری در صفحات نمایش اصلی شما موجود نیست."</string> - <string name="out_of_space" msgid="8365249326091984698">"اتاق دیگری در این صفحه اصلی موجود نیست."</string> + <string name="out_of_space" msgid="8365249326091984698">"اتاق دیگری در این صفحهٔ اصلی موجود نیست."</string> <string name="hotseat_out_of_space" msgid="6304886797358479361">"فضای بیشتری در صندلی داغ نیست."</string> <string name="invalid_hotseat_item" msgid="6545340627805449250">"این ابزارک بیش از حد برای صندلی داغ بزرگ است."</string> <string name="shortcut_installed" msgid="7071557296331322355">"میانبر \"<xliff:g id="NAME">%s</xliff:g>\" ایجاد شد."</string> @@ -50,8 +50,8 @@ <string name="shortcut_duplicate" msgid="4757756326465060694">"میانبر \"<xliff:g id="NAME">%s</xliff:g>\" در حال حاضر وجود دارد."</string> <string name="title_select_shortcut" msgid="1873670208166882222">"انتخاب میانبر"</string> <string name="title_select_application" msgid="1793455815754848652">"انتخاب برنامه"</string> - <string name="all_apps_button_label" msgid="2578400570124163469">"برنامه های کاربردی"</string> - <string name="all_apps_home_button_label" msgid="1022222300329398558">"صفحه اصلی"</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="delete_target_label" msgid="665300185123139530">"حذف"</string> @@ -61,12 +61,12 @@ <string name="accessibility_voice_search_button" msgid="3938249215065842475">"جستجوی صوتی"</string> <string name="accessibility_all_apps_button" msgid="8803738611398979849">"برنامهها"</string> <string name="accessibility_delete_button" msgid="3628162007991023603">"حذف"</string> - <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"حذف نصب به روزرسانی"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"حذف نصب بهروزرسانی"</string> <string name="menu_add" msgid="3065046628354640854">"افزودن"</string> - <string name="menu_manage_apps" msgid="2308685199463588895">"مدیریت برنامه ها"</string> + <string name="menu_manage_apps" msgid="2308685199463588895">"مدیریت برنامهها"</string> <string name="menu_wallpaper" msgid="5837429080911269832">"تصویر زمینه"</string> <string name="menu_search" msgid="4826514464423239041">"جستجو"</string> - <string name="menu_notifications" msgid="6424587053194766192">"اعلان ها"</string> + <string name="menu_notifications" msgid="6424587053194766192">"اعلانها"</string> <string name="menu_settings" msgid="3946232973327980394">"تنظیمات سیستم"</string> <string name="menu_help" msgid="4901160661634590633">"راهنما"</string> <string name="cab_menu_delete_app" msgid="4089398025537640349">"حذف نصب برنامه"</string> @@ -79,27 +79,27 @@ <string name="permdesc_install_shortcut" msgid="8634424803272077038">"به یک برنامه اجازه میدهد میانبرها را بدون دخالت کاربر اضافه کند."</string> <string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"حذف نصب میانبرها"</string> <string name="permdesc_uninstall_shortcut" msgid="274355570620220977">"به یک برنامه اجازه میدهد میانبرها را بدون دخالت کاربر حذف کند."</string> - <string name="permlab_read_settings" msgid="3452408290738106747">"خواندن تنظیمات صفحه اصلی و میانبرها"</string> - <string name="permdesc_read_settings" msgid="5788109303585403679">"به برنامه اجازه خواندن تنظیمات و میانبرها را در صفحه اصلی میدهد."</string> - <string name="permlab_write_settings" msgid="1360567537236705628">"نوشتن تنظیمات صفحه اصلی و میانبرها"</string> - <string name="permdesc_write_settings" msgid="8530105489115785531">"به برنامه اجازه تغییر تنظیمات و میانبرها را در صفحه اصلی میدهد."</string> + <string name="permlab_read_settings" msgid="3452408290738106747">"خواندن تنظیمات صفحهٔ اصلی و میانبرها"</string> + <string name="permdesc_read_settings" msgid="5788109303585403679">"به برنامه اجازه خواندن تنظیمات و میانبرها را در صفحهٔ اصلی میدهد."</string> + <string name="permlab_write_settings" msgid="1360567537236705628">"نوشتن تنظیمات صفحهٔ اصلی و میانبرها"</string> + <string name="permdesc_write_settings" msgid="8530105489115785531">"به برنامه اجازه تغییر تنظیمات و میانبرها را در صفحهٔ اصلی میدهد."</string> <string name="gadget_error_text" msgid="8359351016167075858">"مشکل در بارگیری ابزارک"</string> <string name="uninstall_system_app_text" msgid="6429814133777046491">"این یک برنامه سیستمی است و حذف نصب نمیشود."</string> <string name="dream_name" msgid="2847171357608437154">"پرتاب کننده موشک"</string> <string name="folder_hint_text" msgid="8633351560105748141">"پوشه بینام"</string> - <string name="workspace_description_format" msgid="2968608205939373034">"صفحه اصلی %1$d"</string> + <string name="workspace_description_format" msgid="2968608205939373034">"صفحهٔ اصلی %1$d"</string> <string name="default_scroll_format" msgid="4057140866420001240">"صفحه %1$d از %2$d"</string> - <string name="workspace_scroll_format" msgid="1704767047951143301">"صفحه اصلی %1$d از %2$d"</string> + <string name="workspace_scroll_format" msgid="1704767047951143301">"صفحهٔ اصلی %1$d از %2$d"</string> <string name="apps_customize_apps_scroll_format" msgid="5494241912377704885">"صفحه برنامهها %1$d از %2$d"</string> <string name="apps_customize_widgets_scroll_format" msgid="5383009742241717437">"صفحه ابزارکها %1$d از %2$d"</string> <string name="workspace_cling_title" msgid="738396473989890567">"احساس کنید در خانه هستید"</string> <string name="workspace_cling_move_item" msgid="791013895761065070">"برنامههای مورد دلخواه خود را میتوانید در اینجا قرار دهید."</string> - <string name="workspace_cling_open_all_apps" msgid="2459977609848572588">"برای مشاهده تمام برنامههای خود، حلقه را لمس کنید."</string> + <string name="workspace_cling_open_all_apps" msgid="2459977609848572588">"برای مشاهدهٔ تمام برنامههای خود، حلقه را لمس کنید."</string> <string name="all_apps_cling_title" msgid="2559734712581447107">"انتخاب چند برنامه"</string> - <string name="all_apps_cling_add_item" msgid="5665035103260318891">"برای افزودن یک برنامه به صفحه اصلی خود، آن را لمس کرده و نگه دارید."</string> + <string name="all_apps_cling_add_item" msgid="5665035103260318891">"برای افزودن یک برنامه به صفحهٔ اصلی خود، آن را لمس کرده و نگه دارید."</string> <string name="folder_cling_title" msgid="4308949882377840953">"برنامههای خود را با پوشهها سازماندهی کنید"</string> <string name="folder_cling_move_item" msgid="270598675060435169">"برای جابجا کردن یک برنامه، آن را لمس کرده و نگهدارید."</string> - <string name="folder_cling_create_folder" msgid="8352867485656129478">"برای ایجاد یک پوشه جدید در صفحه اصلی خود، یک برنامه را در بالای دیگری قرار دهید."</string> + <string name="folder_cling_create_folder" msgid="8352867485656129478">"برای ایجاد یک پوشه جدید در صفحهٔ اصلی خود، یک برنامه را در بالای دیگری قرار دهید."</string> <string name="cling_dismiss" msgid="2780907108735868381">"تأیید"</string> <string name="folder_opened" msgid="1262064100943801533">"پوشه باز شده، <xliff:g id="WIDTH">%1$d</xliff:g> در <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="1335478160661137579">"برای بستن پوشه لمس کنید"</string> diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 457ac307d..f72fb5788 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -58,7 +58,7 @@ <string name="delete_target_uninstall_label" msgid="748894921183769150">"Installatie ongedaan maken"</string> <string name="info_target_label" msgid="4019495079517426980">"App-info"</string> <string name="accessibility_search_button" msgid="816822994629942611">"Zoeken"</string> - <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Spraakgestuurd zoeken"</string> + <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Gesproken zoekopdrachten"</string> <string name="accessibility_all_apps_button" msgid="8803738611398979849">"Apps"</string> <string name="accessibility_delete_button" msgid="3628162007991023603">"Verwijderen"</string> <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Update verwijderen"</string> diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml index b67b9c1c0..d07391eeb 100644 --- a/res/values-sw600dp/config.xml +++ b/res/values-sw600dp/config.xml @@ -1,10 +1,10 @@ <resources> - <bool name="allow_rotation">true</bool> - <integer name="cell_count_x">6</integer> <integer name="cell_count_y">6</integer> <integer name="hotseat_cell_count">7</integer> <integer name="hotseat_all_apps_index">3</integer> + <bool name="allow_rotation">true</bool> + <!-- DragController --> <integer name="config_flingToDeleteMinVelocity">-1000</integer> diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml index 7daccd079..4750ae29c 100644 --- a/res/values-sw720dp/dimens.xml +++ b/res/values-sw720dp/dimens.xml @@ -42,9 +42,6 @@ <integer name="apps_customize_maxCellCountY">-1</integer> <dimen name="all_apps_button_vertical_padding">4dip</dimen> - <!-- roughly a status bar (for determining how many rows of icons are in home) --> - <dimen name="status_bar_height">48dip</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> diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index d9ce91529..58fd9d068 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -63,7 +63,7 @@ <string name="accessibility_delete_button" msgid="3628162007991023603">"Kaldır"</string> <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Güncelleme kaldırılsın mı?"</string> <string name="menu_add" msgid="3065046628354640854">"Ekle"</string> - <string name="menu_manage_apps" msgid="2308685199463588895">"Uyglm yönet"</string> + <string name="menu_manage_apps" msgid="2308685199463588895">"Uygulamaları yönet"</string> <string name="menu_wallpaper" msgid="5837429080911269832">"Duvar Kağıdı"</string> <string name="menu_search" msgid="4826514464423239041">"Ara"</string> <string name="menu_notifications" msgid="6424587053194766192">"Bildirimler"</string> diff --git a/res/values/config.xml b/res/values/config.xml index 423a3a96f..7f95931ba 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -1,5 +1,4 @@ <resources> - <bool name="config_hardwareAccelerated">true</bool> <bool name="config_largeHeap">false</bool> <bool name="is_large_screen">false</bool> <bool name="allow_rotation">false</bool> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index f15d3d89b..fb96c0d9f 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -86,10 +86,6 @@ <!-- Drag padding to add to the bottom of drop targets --> <dimen name="drop_target_drag_padding">14dp</dimen> - <!-- roughly a status bar (for vertically centering the all apps - home icon in landscape) --> - <dimen name="status_bar_height">25dip</dimen> - <!-- Dragging --> <!-- the area at the edge of the screen that makes the workspace go left or right while you're dragging. --> diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java deleted file mode 100644 index e8ca61fb3..000000000 --- a/src/com/android/launcher2/AllAppsView.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher2; - -import java.util.ArrayList; - -public interface AllAppsView { - public interface Watcher { - public void zoomed(float zoom); - } - - public void setup(Launcher launcher, DragController dragController); - - public void zoom(float zoom, boolean animate); - - public boolean isVisible(); - - public boolean isAnimating(); - - public void setApps(ArrayList<ApplicationInfo> list); - - public void addApps(ArrayList<ApplicationInfo> list); - - public void removeApps(ArrayList<ApplicationInfo> list); - - public void updateApps(ArrayList<ApplicationInfo> list); - - // Resets the AllApps page to the front - public void reset(); - - public void dumpState(); - - public void surrender(); -} diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java index f94ad019f..2070eb638 100644 --- a/src/com/android/launcher2/AppWidgetResizeFrame.java +++ b/src/com/android/launcher2/AppWidgetResizeFrame.java @@ -415,17 +415,17 @@ public class AppWidgetResizeFrame extends FrameLayout { newHeight); PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX); PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY); - ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y); - ObjectAnimator leftOa = ObjectAnimator.ofFloat(mLeftHandle, "alpha", 1.0f); - ObjectAnimator rightOa = ObjectAnimator.ofFloat(mRightHandle, "alpha", 1.0f); - ObjectAnimator topOa = ObjectAnimator.ofFloat(mTopHandle, "alpha", 1.0f); - ObjectAnimator bottomOa = ObjectAnimator.ofFloat(mBottomHandle, "alpha", 1.0f); + ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(lp, width, height, x, y); + ObjectAnimator leftOa = LauncherAnimUtils.ofFloat(mLeftHandle, "alpha", 1.0f); + ObjectAnimator rightOa = LauncherAnimUtils.ofFloat(mRightHandle, "alpha", 1.0f); + ObjectAnimator topOa = LauncherAnimUtils.ofFloat(mTopHandle, "alpha", 1.0f); + ObjectAnimator bottomOa = LauncherAnimUtils.ofFloat(mBottomHandle, "alpha", 1.0f); oa.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { requestLayout(); } }); - AnimatorSet set = new AnimatorSet(); + AnimatorSet set = LauncherAnimUtils.createAnimatorSet(); if (mResizeMode == AppWidgetProviderInfo.RESIZE_VERTICAL) { set.playTogether(oa, topOa, bottomOa); } else if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) { diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java index 281d59c68..a3040d4cd 100644 --- a/src/com/android/launcher2/ApplicationInfo.java +++ b/src/com/android/launcher2/ApplicationInfo.java @@ -34,11 +34,6 @@ class ApplicationInfo extends ItemInfo { private static final String TAG = "Launcher2.ApplicationInfo"; /** - * The application name. - */ - CharSequence title; - - /** * The intent used to start the application. */ Intent intent; diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java index 8cb169e17..d52c384bd 100644 --- a/src/com/android/launcher2/AppsCustomizePagedView.java +++ b/src/com/android/launcher2/AppsCustomizePagedView.java @@ -17,7 +17,6 @@ package com.android.launcher2; import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; @@ -35,15 +34,12 @@ import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; -import android.graphics.Insets; -import android.graphics.MaskFilter; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; -import android.graphics.TableMaskFilter; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; @@ -60,17 +56,16 @@ import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.GridLayout; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.Toast; import com.android.launcher.R; import com.android.launcher2.DropTarget.DragObject; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.lang.ref.WeakReference; /** * A simple callback interface which also provides the results of the task. @@ -233,7 +228,7 @@ class RectCache extends WeakReferenceThreadLocal<Rect> { * The Apps/Customize page that displays all the applications, widgets, and shortcuts. */ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements - AllAppsView, View.OnClickListener, View.OnKeyListener, DragSource, + View.OnClickListener, View.OnKeyListener, DragSource, PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener, LauncherTransitionable { static final String TAG = "AppsCustomizePagedView"; @@ -267,7 +262,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Caching private Canvas mCanvas; - private Drawable mDefaultWidgetBackground; private IconCache mIconCache; // Dimens @@ -306,6 +300,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen PendingAddWidgetInfo mCreateWidgetInfo = null; private boolean mDraggingWidget = false; + private Toast mWidgetInstructionToast; + // Deferral of loading widget previews during launcher transitions private boolean mInTransition; private ArrayList<AsyncTaskPageData> mDeferredSyncWidgetPageItems = @@ -336,7 +332,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Save the default widget preview background Resources resources = context.getResources(); - mDefaultWidgetBackground = resources.getDrawable(R.drawable.default_widget_preview_holo); mAppIconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0); @@ -528,25 +523,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - public void onPackagesUpdated(boolean immediate) { - if (immediate) { - updatePackages(); - } else { - // TODO: this isn't ideal, but we actually need to delay here. This call is triggered - // by a broadcast receiver, and in order for it to work correctly, we need to know that - // the AppWidgetService has already received and processed the same broadcast. Since there - // is no guarantee about ordering of broadcast receipt, we just delay here. This is a - // workaround until we add a callback from AppWidgetService to AppWidgetHost when widget - // packages are added, updated or removed. - postDelayed(new Runnable() { - public void run() { - updatePackages(); - } - }, 1500); - } - } - - public void updatePackages() { + public void onPackagesUpdated() { // Get the list of widgets and shortcuts mWidgets.clear(); List<AppWidgetProviderInfo> widgets = @@ -602,16 +579,20 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } else if (v instanceof PagedViewWidget) { // Let the user know that they have to long press to add a widget - Toast.makeText(getContext(), R.string.long_press_widget_to_add, - Toast.LENGTH_SHORT).show(); + if (mWidgetInstructionToast != null) { + mWidgetInstructionToast.cancel(); + } + mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add, + Toast.LENGTH_SHORT); + mWidgetInstructionToast.show(); // Create a little animation to show that the widget can move float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); final ImageView p = (ImageView) v.findViewById(R.id.widget_preview); - AnimatorSet bounce = new AnimatorSet(); - ValueAnimator tyuAnim = ObjectAnimator.ofFloat(p, "translationY", offsetY); + AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet(); + ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY); tyuAnim.setDuration(125); - ValueAnimator tydAnim = ObjectAnimator.ofFloat(p, "translationY", 0f); + ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f); tydAnim.setDuration(100); bounce.play(tyuAnim).before(tydAnim); bounce.setInterpolator(new AccelerateInterpolator()); @@ -797,24 +778,17 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen createItemInfo.spanX = createItemInfo.spanY = 1; } - // We use a custom alpha clip table for the default widget previews - Paint alphaClipPaint = null; - if (createItemInfo instanceof PendingAddWidgetInfo) { - if (((PendingAddWidgetInfo) createItemInfo).previewImage != 0) { - MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(0, 255); - alphaClipPaint = new Paint(); - alphaClipPaint.setMaskFilter(alphaClipTable); - } - } + // Don't clip alpha values for the drag outline if we're using the default widget preview + boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo && + (((PendingAddWidgetInfo) createItemInfo).previewImage == 0)); // Save the preview for the outline generation, then dim the preview outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(), false); // Start the drag - alphaClipPaint = null; mLauncher.lockScreenOrientation(); - mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, alphaClipPaint); + mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha); mDragController.startDrag(image, preview, this, createItemInfo, DragController.DRAG_ACTION_COPY, null, scale); outline.recycle(); @@ -1244,7 +1218,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); - float scaleSize = scaledIconWidth / (float) mAppIconSize; renderDrawableToBitmap( icon, tempBitmap, paddingLeft, paddingTop, scaledIconWidth, scaledIconWidth); @@ -1332,7 +1305,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2); if (iconId > 0) icon = mIconCache.getFullResIcon(packageName, iconId); - Resources resources = mLauncher.getResources(); if (icon != null) { renderDrawableToBitmap(icon, defaultPreview, hoffset, yoffset, (int) (mAppIconSize * iconScale), @@ -1692,23 +1664,10 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen /* * AllAppsView implementation */ - @Override public void setup(Launcher launcher, DragController dragController) { mLauncher = launcher; mDragController = dragController; } - @Override - public void zoom(float zoom, boolean animate) { - // TODO-APPS_CUSTOMIZE: Call back to mLauncher.zoomed() - } - @Override - public boolean isVisible() { - return (getVisibility() == VISIBLE); - } - @Override - public boolean isAnimating() { - return false; - } /** * We should call thise method whenever the core data changes (mApps, mWidgets) so that we can @@ -1727,7 +1686,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } - @Override public void setApps(ArrayList<ApplicationInfo> list) { mApps = list; Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR); @@ -1745,7 +1703,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } } - @Override public void addApps(ArrayList<ApplicationInfo> list) { addAppsWithoutInvalidate(list); updatePageCounts(); @@ -1762,6 +1719,16 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } return -1; } + private int findAppByPackage(List<ApplicationInfo> list, String packageName) { + int length = list.size(); + for (int i = 0; i < length; ++i) { + ApplicationInfo info = list.get(i); + if (ItemInfo.getPackageName(info.intent).equals(packageName)) { + return i; + } + } + return -1; + } private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) { // loop through all the apps and remove apps that have the same component int length = list.size(); @@ -1773,13 +1740,21 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } } - @Override - public void removeApps(ArrayList<ApplicationInfo> list) { - removeAppsWithoutInvalidate(list); + private void removeAppsWithPackageNameWithoutInvalidate(ArrayList<String> packageNames) { + // loop through all the package names and remove apps that have the same package name + for (String pn : packageNames) { + int removeIndex = findAppByPackage(mApps, pn); + while (removeIndex > -1) { + mApps.remove(removeIndex); + removeIndex = findAppByPackage(mApps, pn); + } + } + } + public void removeApps(ArrayList<String> packageNames) { + removeAppsWithPackageNameWithoutInvalidate(packageNames); updatePageCounts(); invalidateOnDataChange(); } - @Override public void updateApps(ArrayList<ApplicationInfo> list) { // We remove and re-add the updated applications list because it's properties may have // changed (ie. the title), and this will ensure that the items will be in their proper @@ -1790,7 +1765,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen invalidateOnDataChange(); } - @Override public void reset() { // If we have reset, then we should not continue to restore the previous state mSaveInstanceStateItemIndex = -1; @@ -1812,7 +1786,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane); } - @Override public void dumpState() { // TODO: Dump information related to current list of Applications, Widgets, etc. ApplicationInfo.dumpApplicationInfoList(TAG, "mApps", mApps); @@ -1837,7 +1810,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } } - @Override public void surrender() { // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we // should stop this now. diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java index 144aad98f..5b33c3168 100644 --- a/src/com/android/launcher2/AppsCustomizeTabHost.java +++ b/src/com/android/launcher2/AppsCustomizeTabHost.java @@ -23,7 +23,6 @@ import android.animation.ObjectAnimator; 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; @@ -57,8 +56,6 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona private boolean mResetAfterTransition; private Runnable mRelayoutAndMakeVisible; - private Launcher mLauncher; - public AppsCustomizeTabHost(Context context, AttributeSet attrs) { super(context, attrs); mLayoutInflater = LayoutInflater.from(context); @@ -70,10 +67,6 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona }; } - public void setup(Launcher launcher) { - mLauncher = launcher; - } - /** * Convenience methods to select specific tabs. We want to set the content type immediately * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view @@ -269,7 +262,7 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona onTabChangedEnd(type); // Animate the transition - ObjectAnimator outAnim = ObjectAnimator.ofFloat(mAnimationBuffer, "alpha", 0f); + ObjectAnimator outAnim = LauncherAnimUtils.ofFloat(mAnimationBuffer, "alpha", 0f); outAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -282,14 +275,14 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona mAnimationBuffer.removeAllViews(); } }); - ObjectAnimator inAnim = ObjectAnimator.ofFloat(mAppsCustomizePane, "alpha", 1f); + ObjectAnimator inAnim = LauncherAnimUtils.ofFloat(mAppsCustomizePane, "alpha", 1f); inAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { reloadCurrentPage(); } }); - AnimatorSet animSet = new AnimatorSet(); + AnimatorSet animSet = LauncherAnimUtils.createAnimatorSet(); animSet.playTogether(outAnim, inAnim); animSet.setDuration(duration); animSet.start(); diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java index ddc4b9fa0..c5bed1694 100644 --- a/src/com/android/launcher2/BubbleTextView.java +++ b/src/com/android/launcher2/BubbleTextView.java @@ -111,6 +111,14 @@ public class BubbleTextView extends TextView { } @Override + public void setTag(Object tag) { + if (tag != null) { + LauncherModel.checkItemInfo((ItemInfo) tag); + } + super.setTag(tag); + } + + @Override protected void drawableStateChanged() { if (isPressed()) { // In this case, we have already created the pressed outline on ACTION_DOWN, diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index 97d9bc1b5..fe69e9fd0 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -162,6 +162,7 @@ public class CellLayout extends ViewGroup { private final static PorterDuffXfermode sAddBlendMode = new PorterDuffXfermode(PorterDuff.Mode.ADD); + private final static Paint sPaint = new Paint(); public CellLayout(Context context) { this(context, null); @@ -305,7 +306,15 @@ public class CellLayout extends ViewGroup { } public void enableHardwareLayers() { - mShortcutsAndWidgets.enableHardwareLayers(); + mShortcutsAndWidgets.setLayerType(LAYER_TYPE_HARDWARE, sPaint); + } + + public void disableHardwareLayers() { + mShortcutsAndWidgets.setLayerType(LAYER_TYPE_NONE, sPaint); + } + + public void buildHardwareLayer() { + mShortcutsAndWidgets.buildLayer(); } public void setGridSize(int x, int y) { @@ -1088,7 +1097,7 @@ public class CellLayout extends ViewGroup { return true; } - ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); + ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f); va.setDuration(duration); mReorderAnimators.put(lp, va); @@ -1536,7 +1545,6 @@ public class CellLayout extends ViewGroup { int x = cellX + direction[0]; int y = cellY + direction[1]; while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) { - boolean fail = false; for (int i = 0; i < spanX; i++) { for (int j = 0; j < spanY; j++) { @@ -1579,8 +1587,9 @@ public class CellLayout extends ViewGroup { return success; } - // This method looks in the specified direction to see if there is an additional view - // immediately adjecent in that direction + // This method looks in the specified direction to see if there are additional views adjacent + // to the current set of views in the. If there is, then these views are added to the current + // set of views. This is performed iteratively, giving a cascading push behaviour. private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction, boolean[][] occupied, View dragView, ItemConfiguration currentState) { boolean found = false; @@ -1589,23 +1598,27 @@ public class CellLayout extends ViewGroup { Rect r0 = new Rect(boundingRect); Rect r1 = new Rect(); + // First, we consider the rect of the views that we are trying to translate int deltaX = 0; int deltaY = 0; if (direction[1] < 0) { - r0.set(r0.left, r0.top - 1, r0.right, r0.bottom); + r0.set(r0.left, r0.top - 1, r0.right, r0.bottom - 1); deltaY = -1; } else if (direction[1] > 0) { - r0.set(r0.left, r0.top, r0.right, r0.bottom + 1); + r0.set(r0.left, r0.top + 1, r0.right, r0.bottom + 1); deltaY = 1; } else if (direction[0] < 0) { - r0.set(r0.left - 1, r0.top, r0.right, r0.bottom); + r0.set(r0.left - 1, r0.top, r0.right - 1, r0.bottom); deltaX = -1; } else if (direction[0] > 0) { - r0.set(r0.left, r0.top, r0.right + 1, r0.bottom); + r0.set(r0.left + 1, r0.top, r0.right + 1, r0.bottom); deltaX = 1; } + // Now we see which views, if any, are being overlapped by shifting the current group + // of views in the desired direction. for (int i = 0; i < childCount; i++) { + // We don't need to worry about views already in our group, or the current drag view. View child = mShortcutsAndWidgets.getChildAt(i); if (views.contains(child) || child == dragView) continue; CellAndSpan c = currentState.map.get(child); @@ -1616,20 +1629,30 @@ public class CellLayout extends ViewGroup { if (!lp.canReorder) { return false; } - boolean pushed = false; - for (int x = c.x; x < c.x + c.spanX; x++) { - for (int y = c.y; y < c.y + c.spanY; y++) { - boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX - && y - deltaY >= 0 && y - deltaY < mCountY; - if (inBounds && occupied[x - deltaX][y - deltaY]) { - pushed = true; + // First we verify that the view in question is at the border of the extents + // of the block of items we are pushing + if ((direction[0] < 0 && c.x == r0.left) || + (direction[0] > 0 && c.x == r0.right - 1) || + (direction[1] < 0 && c.y == r0.top) || + (direction[1] > 0 && c.y == r0.bottom - 1)) { + boolean pushed = false; + // Since the bounding rect is a course description of the region (there can + // be holes at the edge of the block), we need to check to verify that a solid + // piece is intersecting. This ensures that interlocking is possible. + for (int x = c.x; x < c.x + c.spanX; x++) { + for (int y = c.y; y < c.y + c.spanY; y++) { + if (occupied[x - deltaX][y - deltaY]) { + pushed = true; + break; + } + if (pushed) break; } } - } - if (pushed) { - views.add(child); - boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); - found = true; + if (pushed) { + views.add(child); + boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); + found = true; + } } } } @@ -1670,7 +1693,7 @@ public class CellLayout extends ViewGroup { int top = boundingRect.top; int left = boundingRect.left; // We mark more precisely which parts of the bounding rect are truly occupied, allowing - // for tetris-style interlocking. + // for interlocking. for (View v: dup) { CellAndSpan c = currentState.map.get(v); markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true); @@ -2070,7 +2093,7 @@ public class CellLayout extends ViewGroup { if (finalDeltaX == 0 && finalDeltaY == 0) { return; } - ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); + ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f); a = va; va.setRepeatMode(ValueAnimator.REVERSE); va.setRepeatCount(ValueAnimator.INFINITE); @@ -2112,13 +2135,13 @@ public class CellLayout extends ViewGroup { a.cancel(); } - AnimatorSet s = new AnimatorSet(); + AnimatorSet s = LauncherAnimUtils.createAnimatorSet(); a = s; s.playTogether( - ObjectAnimator.ofFloat(child, "scaleX", 1f), - ObjectAnimator.ofFloat(child, "scaleY", 1f), - ObjectAnimator.ofFloat(child, "translationX", 0f), - ObjectAnimator.ofFloat(child, "translationY", 0f) + LauncherAnimUtils.ofFloat(child, "scaleX", 1f), + LauncherAnimUtils.ofFloat(child, "scaleY", 1f), + LauncherAnimUtils.ofFloat(child, "translationX", 0f), + LauncherAnimUtils.ofFloat(child, "translationY", 0f) ); s.setDuration(REORDER_ANIMATION_DURATION); s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f)); @@ -2147,6 +2170,10 @@ public class CellLayout extends ViewGroup { // We do a null check here because the item info can be null in the case of the // AllApps button in the hotseat. if (info != null) { + if (info.cellX != lp.tmpCellX || info.cellY != lp.tmpCellY || + info.spanX != lp.cellHSpan || info.spanY != lp.cellVSpan) { + info.requiresDbUpdate = true; + } info.cellX = lp.cellX = lp.tmpCellX; info.cellY = lp.cellY = lp.tmpCellY; info.spanX = lp.cellHSpan; diff --git a/src/com/android/launcher2/Cling.java b/src/com/android/launcher2/Cling.java index 646c54e90..971d9ff53 100644 --- a/src/com/android/launcher2/Cling.java +++ b/src/com/android/launcher2/Cling.java @@ -31,7 +31,6 @@ import android.util.DisplayMetrics; import android.view.FocusFinder; import android.view.MotionEvent; import android.view.View; -import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import com.android.launcher.R; @@ -83,6 +82,8 @@ public class Cling extends FrameLayout { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Cling, defStyle, 0); mDrawIdentifier = a.getString(R.styleable.Cling_drawIdentifier); a.recycle(); + + setClickable(true); } void init(Launcher l, int[] positionData) { @@ -138,16 +139,8 @@ public class Cling extends FrameLayout { } @Override - public View findViewToTakeAccessibilityFocusFromHover(View child, View descendant) { - if (descendant.includeForAccessibility()) { - return descendant; - } - return null; - } - - @Override public View focusSearch(int direction) { - return this.focusSearch(null, direction); + return this.focusSearch(this, direction); } @Override diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java index 949c035ea..39a0b09c7 100644 --- a/src/com/android/launcher2/DeleteDropTarget.java +++ b/src/com/android/launcher2/DeleteDropTarget.java @@ -25,7 +25,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; import android.util.AttributeSet; import android.view.View; diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java index 84f151581..4c4295319 100644 --- a/src/com/android/launcher2/DragController.java +++ b/src/com/android/launcher2/DragController.java @@ -326,19 +326,17 @@ public class DragController { } endDrag(); } - public void onAppsRemoved(ArrayList<ApplicationInfo> apps, Context context) { + public void onAppsRemoved(ArrayList<String> packageNames, Context context) { // Cancel the current drag if we are removing an app that we are dragging if (mDragObject != null) { Object rawDragInfo = mDragObject.dragInfo; if (rawDragInfo instanceof ShortcutInfo) { ShortcutInfo dragInfo = (ShortcutInfo) rawDragInfo; - for (ApplicationInfo info : apps) { + for (String pn : packageNames) { // Added null checks to prevent NPE we've seen in the wild if (dragInfo != null && - dragInfo.intent != null && - info.intent != null) { - boolean isSamePackage = dragInfo.getPackageName().equals( - info.getPackageName()); + dragInfo.intent != null) { + boolean isSamePackage = dragInfo.getPackageName().equals(pn); if (isSamePackage) { cancelDrag(); return; diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java index 4be1914e0..0bcd64c41 100644 --- a/src/com/android/launcher2/DragLayer.java +++ b/src/com/android/launcher2/DragLayer.java @@ -24,8 +24,6 @@ import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; @@ -446,7 +444,6 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang public void animateViewIntoPosition(DragView dragView, final View child, int duration, final Runnable onFinishAnimationRunnable, View anchorView) { ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent(); - CellLayout parent = (CellLayout) (CellLayout) parentChildren.getParent(); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); parentChildren.measureChild(child); diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java index b6645e102..389421d52 100644 --- a/src/com/android/launcher2/DragView.java +++ b/src/com/android/launcher2/DragView.java @@ -76,7 +76,7 @@ public class DragView extends View { final float scale = (width + scaleDps) / width; // Animate the view into the correct position - mAnim = ValueAnimator.ofFloat(0.0f, 1.0f); + mAnim = LauncherAnimUtils.ofFloat(0.0f, 1.0f); mAnim.setDuration(150); mAnim.addUpdateListener(new AnimatorUpdateListener() { @Override @@ -199,7 +199,7 @@ public class DragView extends View { } public void crossFade(int duration) { - ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); + ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f); va.setDuration(duration); va.setInterpolator(new DecelerateInterpolator(1.5f)); va.addUpdateListener(new AnimatorUpdateListener() { @@ -244,9 +244,6 @@ public class DragView extends View { public void show(int touchX, int touchY) { mDragLayer.addView(this); - // Enable hw-layers on this view - setLayerType(View.LAYER_TYPE_HARDWARE, null); - // Start the pick-up animation DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0); lp.width = mBitmap.getWidth(); @@ -255,7 +252,12 @@ public class DragView extends View { setLayoutParams(lp); setTranslationX(touchX - mRegistrationX); setTranslationY(touchY - mRegistrationY); - mAnim.start(); + // Post the animation to skip other expensive work happening on the first frame + post(new Runnable() { + public void run() { + mAnim.start(); + } + }); } public void cancelAnimation() { @@ -282,9 +284,6 @@ public class DragView extends View { void remove() { if (getParent() != null) { - // Disable hw-layers on this view - setLayerType(View.LAYER_TYPE_NONE, null); - mDragLayer.removeView(DragView.this); } } diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java index de2e4359a..8aa6e2f62 100644 --- a/src/com/android/launcher2/Folder.java +++ b/src/com/android/launcher2/Folder.java @@ -57,8 +57,6 @@ import java.util.Comparator; public class Folder extends LinearLayout implements DragSource, View.OnClickListener, View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener, View.OnFocusChangeListener { - - @SuppressWarnings("unused") private static final String TAG = "Launcher.Folder"; protected DragController mDragController; @@ -110,6 +108,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private static String sHintText; private ObjectAnimator mOpenCloseAnimator; + private boolean mDestroyed; + /** * Used to inflate the Workspace from XML. * @@ -421,7 +421,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f); PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f); final ObjectAnimator oa = mOpenCloseAnimator = - ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY); + LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY); oa.addListener(new AnimatorListenerAdapter() { @Override @@ -479,7 +479,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f); PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f); final ObjectAnimator oa = mOpenCloseAnimator = - ObjectAnimator.ofPropertyValuesHolder(this, alpha, scaleX, scaleY); + LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY); oa.addListener(new AnimatorListenerAdapter() { @Override @@ -945,34 +945,47 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } private void replaceFolderWithFinalItem() { - ItemInfo finalItem = null; - - if (getItemCount() == 1) { - finalItem = mInfo.contents.get(0); - } - - // Remove the folder completely - CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen); - cellLayout.removeView(mFolderIcon); - if (mFolderIcon instanceof DropTarget) { - mDragController.removeDropTarget((DropTarget) mFolderIcon); - } - mLauncher.removeFolder(mInfo); - - if (finalItem != null) { - LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container, - mInfo.screen, mInfo.cellX, mInfo.cellY); - } - LauncherModel.deleteItemFromDatabase(mLauncher, mInfo); - // Add the last remaining child to the workspace in place of the folder - if (finalItem != null) { - View child = mLauncher.createShortcut(R.layout.application, cellLayout, - (ShortcutInfo) finalItem); - - mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screen, mInfo.cellX, - mInfo.cellY, mInfo.spanX, mInfo.spanY); + Runnable onCompleteRunnable = new Runnable() { + @Override + public void run() { + CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen); + + View child = null; + // Move the item from the folder to the workspace, in the position of the folder + if (getItemCount() == 1) { + ShortcutInfo finalItem = mInfo.contents.get(0); + child = mLauncher.createShortcut(R.layout.application, cellLayout, + finalItem); + LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container, + mInfo.screen, mInfo.cellX, mInfo.cellY); + } + if (getItemCount() <= 1) { + // Remove the folder + LauncherModel.deleteItemFromDatabase(mLauncher, mInfo); + cellLayout.removeView(mFolderIcon); + if (mFolderIcon instanceof DropTarget) { + mDragController.removeDropTarget((DropTarget) mFolderIcon); + } + mLauncher.removeFolder(mInfo); + } + // We add the child after removing the folder to prevent both from existing at + // the same time in the CellLayout. + if (child != null) { + mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screen, + mInfo.cellX, mInfo.cellY, mInfo.spanX, mInfo.spanY); + } + } + }; + View finalChild = getItemAt(0); + if (finalChild != null) { + mFolderIcon.performDestroyAnimation(finalChild, onCompleteRunnable); } + mDestroyed = true; + } + + boolean isDestroyed() { + return mDestroyed; } // This method keeps track of the last item in the folder for the purposes diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java index 4919b57f0..05921dc1c 100644 --- a/src/com/android/launcher2/FolderIcon.java +++ b/src/com/android/launcher2/FolderIcon.java @@ -50,8 +50,8 @@ import java.util.ArrayList; */ public class FolderIcon extends LinearLayout implements FolderListener { private Launcher mLauncher; - Folder mFolder; - FolderInfo mInfo; + private Folder mFolder; + private FolderInfo mInfo; private static boolean sStaticValuesDirty = true; private CheckLongPressHelper mLongPressHelper; @@ -61,6 +61,7 @@ public class FolderIcon extends LinearLayout implements FolderListener { private static final int CONSUMPTION_ANIMATION_DURATION = 100; private static final int DROP_IN_ANIMATION_DURATION = 400; private static final int INITIAL_ITEM_ANIMATION_DURATION = 350; + private static final int FINAL_ITEM_ANIMATION_DURATION = 200; // The degree to which the inner ring grows when accepting drop private static final float INNER_RING_GROWTH_FACTOR = 0.15f; @@ -93,8 +94,10 @@ public class FolderIcon extends LinearLayout implements FolderListener { private int mPreviewOffsetY; private float mMaxPerspectiveShift; boolean mAnimating = false; + private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0); private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0); + private ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>(); public FolderIcon(Context context, AttributeSet attrs) { super(context, attrs); @@ -196,7 +199,7 @@ public class FolderIcon extends LinearLayout implements FolderListener { if (mNeutralAnimator != null) { mNeutralAnimator.cancel(); } - mAcceptAnimator = ValueAnimator.ofFloat(0f, 1f); + mAcceptAnimator = LauncherAnimUtils.ofFloat(0f, 1f); mAcceptAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION); final int previewSize = sPreviewSize; @@ -225,7 +228,7 @@ public class FolderIcon extends LinearLayout implements FolderListener { if (mAcceptAnimator != null) { mAcceptAnimator.cancel(); } - mNeutralAnimator = ValueAnimator.ofFloat(0f, 1f); + mNeutralAnimator = LauncherAnimUtils.ofFloat(0f, 1f); mNeutralAnimator.setDuration(CONSUMPTION_ANIMATION_DURATION); final int previewSize = sPreviewSize; @@ -278,6 +281,14 @@ public class FolderIcon extends LinearLayout implements FolderListener { } } + Folder getFolder() { + return mFolder; + } + + FolderInfo getFolderInfo() { + return mInfo; + } + private boolean willAcceptItem(ItemInfo item) { final int itemType = item.itemType; return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || @@ -287,16 +298,15 @@ public class FolderIcon extends LinearLayout implements FolderListener { public boolean acceptDrop(Object dragInfo) { final ItemInfo item = (ItemInfo) dragInfo; - return willAcceptItem(item); + return !mFolder.isDestroyed() && willAcceptItem(item); } public void addItem(ShortcutInfo item) { mInfo.add(item); - LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY); } public void onDragEnter(Object dragInfo) { - if (!willAcceptItem((ItemInfo) dragInfo)) return; + if (mFolder.isDestroyed() || !willAcceptItem((ItemInfo) dragInfo)) return; CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); CellLayout layout = (CellLayout) getParent().getParent(); mFolderRingAnimator.setCell(lp.cellX, lp.cellY); @@ -312,16 +322,29 @@ public class FolderIcon extends LinearLayout implements FolderListener { final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect, float scaleRelativeToDragLayer, Runnable postAnimationRunnable) { + // These correspond two the drawable and view that the icon was dropped _onto_ Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1]; - computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth()); + computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), + destView.getMeasuredWidth()); + + // This will animate the first item from it's position as an icon into its + // position as the first item in the preview + animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION, false, null); + addItem(destInfo); // This will animate the dragView (srcView) into the new folder onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, postAnimationRunnable, null); + } + + public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) { + Drawable animateDrawable = ((TextView) finalView).getCompoundDrawables()[1]; + computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), + finalView.getMeasuredWidth()); // This will animate the first item from it's position as an icon into its // position as the first item in the preview - animateFirstItem(animateDrawable, INITIAL_ITEM_ANIMATION_DURATION); - addItem(destInfo); + animateFirstItem(animateDrawable, FINAL_ITEM_ANIMATION_DURATION, true, + onCompleteRunnable); } public void onDragExit(Object dragInfo) { @@ -377,9 +400,12 @@ public class FolderIcon extends LinearLayout implements FolderListener { 1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION, new DecelerateInterpolator(2), new AccelerateInterpolator(2), postAnimationRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null); + addItem(item); + mHiddenItems.add(item); postDelayed(new Runnable() { public void run() { - addItem(item); + mHiddenItems.remove(item); + invalidate(); } }, DROP_IN_ANIMATION_DURATION); } else { @@ -526,19 +552,20 @@ public class FolderIcon extends LinearLayout implements FolderListener { if (!mAnimating) { for (int i = nItemsInPreview - 1; i >= 0; i--) { v = (TextView) items.get(i); - d = v.getCompoundDrawables()[1]; - - mParams = computePreviewItemDrawingParams(i, mParams); - mParams.drawable = d; - drawPreviewItem(canvas, mParams); + if (!mHiddenItems.contains(v.getTag())) { + d = v.getCompoundDrawables()[1]; + mParams = computePreviewItemDrawingParams(i, mParams); + mParams.drawable = d; + drawPreviewItem(canvas, mParams); + } } } else { drawPreviewItem(canvas, mAnimParams); } } - private void animateFirstItem(final Drawable d, int duration) { - computePreviewDrawingParams(d); + private void animateFirstItem(final Drawable d, int duration, final boolean reverse, + final Runnable onCompleteRunnable) { final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null); final float scale0 = 1.0f; @@ -546,10 +573,14 @@ public class FolderIcon extends LinearLayout implements FolderListener { final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2; mAnimParams.drawable = d; - ValueAnimator va = ValueAnimator.ofFloat(0f, 1.0f); + ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1.0f); va.addUpdateListener(new AnimatorUpdateListener(){ public void onAnimationUpdate(ValueAnimator animation) { float progress = (Float) animation.getAnimatedValue(); + if (reverse) { + progress = 1 - progress; + mPreviewBackground.setAlpha(progress); + } mAnimParams.transX = transX0 + progress * (finalParams.transX - transX0); mAnimParams.transY = transY0 + progress * (finalParams.transY - transY0); @@ -565,6 +596,9 @@ public class FolderIcon extends LinearLayout implements FolderListener { @Override public void onAnimationEnd(Animator animation) { mAnimating = false; + if (onCompleteRunnable != null) { + onCompleteRunnable.run(); + } } }); va.setDuration(duration); diff --git a/src/com/android/launcher2/FolderInfo.java b/src/com/android/launcher2/FolderInfo.java index f59707671..dbac90ec5 100644 --- a/src/com/android/launcher2/FolderInfo.java +++ b/src/com/android/launcher2/FolderInfo.java @@ -31,11 +31,6 @@ class FolderInfo extends ItemInfo { boolean opened; /** - * The folder name. - */ - CharSequence title; - - /** * The apps and shortcuts */ ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>(); diff --git a/src/com/android/launcher2/HolographicOutlineHelper.java b/src/com/android/launcher2/HolographicOutlineHelper.java index 56d194d4e..1e990dcff 100644 --- a/src/com/android/launcher2/HolographicOutlineHelper.java +++ b/src/com/android/launcher2/HolographicOutlineHelper.java @@ -19,17 +19,14 @@ 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; public static final int MIN_OUTER_BLUR_RADIUS; @@ -61,8 +58,6 @@ public class HolographicOutlineHelper { sMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL); } - private int[] mTempOffset = new int[2]; - HolographicOutlineHelper() { mHolographicPaint.setFilterBitmap(true); mHolographicPaint.setAntiAlias(true); @@ -71,8 +66,6 @@ public class HolographicOutlineHelper { mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); mErasePaint.setFilterBitmap(true); mErasePaint.setAntiAlias(true); - MaskFilter alphaClipTable = TableMaskFilter.CreateClipTable(180, 255); - mAlphaClipPaint.setMaskFilter(alphaClipTable); } /** @@ -102,18 +95,28 @@ public class HolographicOutlineHelper { */ void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, int outlineColor, int thickness) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, mAlphaClipPaint, + applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true, thickness); } void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor, Paint alphaClipPaint, int thickness) { + int outlineColor, boolean clipAlpha, 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 - if (alphaClipPaint == null) { - alphaClipPaint = mAlphaClipPaint; + if (clipAlpha) { + int[] srcBuffer = new int[srcDst.getWidth() * srcDst.getHeight()]; + srcDst.getPixels(srcBuffer, + 0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight()); + for (int i = 0; i < srcBuffer.length; i++) { + final int alpha = srcBuffer[i] >>> 24; + if (alpha < 188) { + srcBuffer[i] = 0; + } + } + srcDst.setPixels(srcBuffer, + 0, srcDst.getWidth(), 0, 0, srcDst.getWidth(), srcDst.getHeight()); } - Bitmap glowShape = srcDst.extractAlpha(alphaClipPaint, mTempOffset); + Bitmap glowShape = srcDst.extractAlpha(); // calculate the outer blur first BlurMaskFilter outerBlurMaskFilter; @@ -205,8 +208,8 @@ public class HolographicOutlineHelper { } void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor, Paint alphaClipPaint) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, alphaClipPaint, + int outlineColor, boolean clipAlpha) { + applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha, MEDIUM); } diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java index a525d00ee..20a19660e 100644 --- a/src/com/android/launcher2/InstallShortcutReceiver.java +++ b/src/com/android/launcher2/InstallShortcutReceiver.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; -import android.os.Debug; import android.widget.Toast; import com.android.launcher.R; diff --git a/src/com/android/launcher2/InterruptibleInOutAnimator.java b/src/com/android/launcher2/InterruptibleInOutAnimator.java index 135fa3996..9831ba3d4 100644 --- a/src/com/android/launcher2/InterruptibleInOutAnimator.java +++ b/src/com/android/launcher2/InterruptibleInOutAnimator.java @@ -45,7 +45,7 @@ public class InterruptibleInOutAnimator { private int mDirection = STOPPED; public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) { - mAnimator = ValueAnimator.ofFloat(fromValue, toValue).setDuration(duration); + mAnimator = LauncherAnimUtils.ofFloat(fromValue, toValue).setDuration(duration); mOriginalDuration = duration; mOriginalFromValue = fromValue; mOriginalToValue = toValue; diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java index dedc0f4f3..f9ae3686e 100644 --- a/src/com/android/launcher2/ItemInfo.java +++ b/src/com/android/launcher2/ItemInfo.java @@ -86,10 +86,16 @@ class ItemInfo { * Indicates the minimum Y cell span. */ int minSpanY = 1; + + /** + * Indicates that this item needs to be updated in the db + */ + boolean requiresDbUpdate = false; + /** - * Indicates whether the item is a gesture. + * Title of the item */ - boolean isGesture = false; + CharSequence title; /** * The position of the item in a drag-and-drop operation. @@ -132,14 +138,12 @@ class ItemInfo { */ void onAddToDatabase(ContentValues values) { values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType); - if (!isGesture) { - values.put(LauncherSettings.Favorites.CONTAINER, container); - values.put(LauncherSettings.Favorites.SCREEN, screen); - values.put(LauncherSettings.Favorites.CELLX, cellX); - values.put(LauncherSettings.Favorites.CELLY, cellY); - values.put(LauncherSettings.Favorites.SPANX, spanX); - values.put(LauncherSettings.Favorites.SPANY, spanY); - } + values.put(LauncherSettings.Favorites.CONTAINER, container); + values.put(LauncherSettings.Favorites.SCREEN, screen); + values.put(LauncherSettings.Favorites.CELLX, cellX); + values.put(LauncherSettings.Favorites.CELLY, cellY); + values.put(LauncherSettings.Favorites.SPANX, spanX); + values.put(LauncherSettings.Favorites.SPANY, spanY); } void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) { @@ -183,6 +187,6 @@ class ItemInfo { public String toString() { return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container + " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX - + " spanY=" + spanY + " isGesture=" + isGesture + " dropPos=" + dropPos + ")"; + + " spanY=" + spanY + " dropPos=" + dropPos + ")"; } } diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 38085e029..9999e0fe3 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -61,11 +61,11 @@ import android.os.Handler; import android.os.Message; import android.os.StrictMode; import android.os.SystemClock; -import android.os.SystemProperties; import android.provider.Settings; import android.speech.RecognizerIntent; import android.text.Selection; import android.text.SpannableStringBuilder; +import android.text.TextUtils; import android.text.method.TextKeyListener; import android.util.Log; import android.view.Display; @@ -99,6 +99,7 @@ import com.android.launcher2.DropTarget.DragObject; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileDescriptor; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; @@ -116,7 +117,7 @@ import java.util.Set; */ public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, - AllAppsView.Watcher, View.OnTouchListener { + View.OnTouchListener { static final String TAG = "Launcher"; static final boolean LOGD = false; @@ -145,7 +146,8 @@ public final class Launcher extends Activity static final int DEFAULT_SCREEN = 2; private static final String PREFERENCES = "launcher.preferences"; - static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher.force_enable_rotation"; + static final String FORCE_ENABLE_ROTATION_PROPERTY = "debug.force_enable_rotation"; + static final String DUMP_STATE_PROPERTY = "debug.dumpstate"; // The Intent extra that defines whether to ignore the launch animation static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION = @@ -317,6 +319,20 @@ public final class Launcher extends Activity int cellY; } + + private boolean doesFileExist(String filename) { + FileInputStream fis = null; + try { + fis = openFileInput(filename); + fis.close(); + return true; + } catch (java.io.FileNotFoundException e) { + return false; + } catch (java.io.IOException e) { + return true; + } + } + @Override protected void onCreate(Bundle savedInstanceState) { if (DEBUG_STRICT_MODE) { @@ -371,7 +387,7 @@ public final class Launcher extends Activity // Update customization drawer _after_ restoring the states if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.onPackagesUpdated(true); + mAppsCustomizeContent.onPackagesUpdated(); } if (PROFILE_STARTUP) { @@ -935,7 +951,6 @@ public final class Launcher extends Activity findViewById(R.id.apps_customize_pane); mAppsCustomizeContent = (AppsCustomizePagedView) mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content); - mAppsCustomizeTabHost.setup(this); mAppsCustomizeContent.setup(this, dragController); // Get the all apps button @@ -1494,7 +1509,7 @@ public final class Launcher extends Activity mWorkspace = null; mDragController = null; - ValueAnimator.clearAllAnimations(); + LauncherAnimUtils.onDestroyActivity(); } public DragController getDragController() { @@ -1527,10 +1542,48 @@ public final class Launcher extends Activity } Rect sourceBounds = mSearchDropTargetBar.getSearchBarBounds(); + startGlobalSearch(initialQuery, selectInitialQuery, + appSearchData, sourceBounds); + } + + /** + * Starts the global search activity. This code is a copied from SearchManager + */ + public void startGlobalSearch(String initialQuery, + boolean selectInitialQuery, Bundle appSearchData, Rect sourceBounds) { final SearchManager searchManager = - (SearchManager) getSystemService(Context.SEARCH_SERVICE); - searchManager.startSearch(initialQuery, selectInitialQuery, getComponentName(), - appSearchData, globalSearch, sourceBounds); + (SearchManager) getSystemService(Context.SEARCH_SERVICE); + ComponentName globalSearchActivity = searchManager.getGlobalSearchActivity(); + if (globalSearchActivity == null) { + Log.w(TAG, "No global search activity found."); + return; + } + Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setComponent(globalSearchActivity); + // Make sure that we have a Bundle to put source in + if (appSearchData == null) { + appSearchData = new Bundle(); + } else { + appSearchData = new Bundle(appSearchData); + } + // Set source to package name of app that starts global search, if not set already. + if (!appSearchData.containsKey("source")) { + appSearchData.putString("source", getPackageName()); + } + intent.putExtra(SearchManager.APP_DATA, appSearchData); + if (!TextUtils.isEmpty(initialQuery)) { + intent.putExtra(SearchManager.QUERY, initialQuery); + } + if (selectInitialQuery) { + intent.putExtra(SearchManager.EXTRA_SELECT_QUERY, selectInitialQuery); + } + intent.setSourceBounds(sourceBounds); + try { + startActivity(intent); + } catch (ActivityNotFoundException ex) { + Log.e(TAG, "Global search activity not found: " + globalSearchActivity); + } } @Override @@ -1788,7 +1841,7 @@ public final class Launcher extends Activity case KeyEvent.KEYCODE_HOME: return true; case KeyEvent.KEYCODE_VOLUME_DOWN: - if (SystemProperties.getInt("debug.launcher2.dumpstate", 0) != 0) { + if (doesFileExist(DUMP_STATE_PROPERTY)) { dumpState(); return true; } @@ -2031,7 +2084,7 @@ public final class Launcher extends Activity } private void handleFolderClick(FolderIcon folderIcon) { - final FolderInfo info = folderIcon.mInfo; + final FolderInfo info = folderIcon.getFolderInfo(); Folder openFolder = mWorkspace.getFolderForTag(info); // If the folder info reports that the associated folder is open, then verify that @@ -2042,7 +2095,7 @@ public final class Launcher extends Activity info.opened = false; } - if (!info.opened) { + if (!info.opened && !folderIcon.getFolder().isDestroyed()) { // Close any open folder closeFolder(); // Open the requested folder @@ -2099,9 +2152,9 @@ public final class Launcher extends Activity mFolderIconCanvas.drawColor(0, PorterDuff.Mode.CLEAR); fi.draw(mFolderIconCanvas); mFolderIconImageView.setImageBitmap(mFolderIconBitmap); - if (fi.mFolder != null) { - mFolderIconImageView.setPivotX(fi.mFolder.getPivotXForIconAnimation()); - mFolderIconImageView.setPivotY(fi.mFolder.getPivotYForIconAnimation()); + if (fi.getFolder() != null) { + mFolderIconImageView.setPivotX(fi.getFolder().getPivotXForIconAnimation()); + mFolderIconImageView.setPivotY(fi.getFolder().getPivotYForIconAnimation()); } // Just in case this image view is still in the drag layer from a previous animation, // we remove it and re-add it. @@ -2109,8 +2162,8 @@ public final class Launcher extends Activity mDragLayer.removeView(mFolderIconImageView); } mDragLayer.addView(mFolderIconImageView, lp); - if (fi.mFolder != null) { - fi.mFolder.bringToFront(); + if (fi.getFolder() != null) { + fi.getFolder().bringToFront(); } } @@ -2131,7 +2184,7 @@ public final class Launcher extends Activity copyFolderIconToImage(fi); fi.setVisibility(View.INVISIBLE); - ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(mFolderIconImageView, alpha, + ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha, scaleX, scaleY); oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration)); oa.start(); @@ -2148,7 +2201,7 @@ public final class Launcher extends Activity // We remove and re-draw the FolderIcon in-case it has changed mDragLayer.removeView(mFolderIconImageView); copyFolderIconToImage(fi); - ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(mFolderIconImageView, alpha, + ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha, scaleX, scaleY); oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration)); oa.addListener(new AnimatorListenerAdapter() { @@ -2173,7 +2226,7 @@ public final class Launcher extends Activity * @param folderInfo The FolderInfo describing the folder to open. */ public void openFolder(FolderIcon folderIcon) { - Folder folder = folderIcon.mFolder; + Folder folder = folderIcon.getFolder(); FolderInfo info = folder.mInfo; info.opened = true; @@ -2290,13 +2343,6 @@ public final class Launcher extends Activity return mHotseat.isAllAppsButtonRank(rank); } - // AllAppsView.Watcher - public void zoomed(float zoom) { - if (zoom == 1.0f) { - mWorkspace.setVisibility(View.GONE); - } - } - /** * Helper method for the cameraZoomIn/cameraZoomOut animations * @param view The view being animated @@ -2449,7 +2495,7 @@ public final class Launcher extends Activity // toView should appear right at the end of the workspace shrink // animation - mStateAnimation = new AnimatorSet(); + mStateAnimation = LauncherAnimUtils.createAnimatorSet(); mStateAnimation.play(scaleAnim).after(startDelay); mStateAnimation.play(alphaAnim).after(startDelay); @@ -2624,7 +2670,7 @@ public final class Launcher extends Activity } }); - mStateAnimation = new AnimatorSet(); + mStateAnimation = LauncherAnimUtils.createAnimatorSet(); dispatchOnLauncherTransitionPrepare(fromView, animated, true); dispatchOnLauncherTransitionPrepare(toView, animated, true); @@ -2808,9 +2854,9 @@ public final class Launcher extends Activity mDividerAnimator = null; } if (animated) { - mDividerAnimator = new AnimatorSet(); - mDividerAnimator.playTogether(ObjectAnimator.ofFloat(mQsbDivider, "alpha", 1f), - ObjectAnimator.ofFloat(mDockDivider, "alpha", 1f)); + mDividerAnimator = LauncherAnimUtils.createAnimatorSet(); + mDividerAnimator.playTogether(LauncherAnimUtils.ofFloat(mQsbDivider, "alpha", 1f), + LauncherAnimUtils.ofFloat(mDockDivider, "alpha", 1f)); mDividerAnimator.setDuration(mSearchDropTargetBar.getTransitionInDuration()); mDividerAnimator.start(); } @@ -3385,7 +3431,7 @@ public final class Launcher extends Activity * @param immediate whether to run the animation or show the results immediately */ private void runNewAppsAnimation(boolean immediate) { - AnimatorSet anim = new AnimatorSet(); + AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); Collection<Animator> bounceAnims = new ArrayList<Animator>(); // Order these new views spatially so that they animate in order @@ -3409,7 +3455,7 @@ public final class Launcher extends Activity } else { for (int i = 0; i < mNewShortcutAnimateViews.size(); ++i) { View v = mNewShortcutAnimateViews.get(i); - ValueAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder(v, + ValueAnimator bounceAnim = LauncherAnimUtils.ofPropertyValuesHolder(v, PropertyValuesHolder.ofFloat("alpha", 1f), PropertyValuesHolder.ofFloat("scaleX", 1f), PropertyValuesHolder.ofFloat("scaleY", 1f)); @@ -3514,17 +3560,17 @@ public final class Launcher extends Activity * * Implementation of the method from LauncherModel.Callbacks. */ - public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent) { + public void bindAppsRemoved(ArrayList<String> packageNames, boolean permanent) { if (permanent) { - mWorkspace.removeItems(apps); + mWorkspace.removeItems(packageNames); } if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.removeApps(apps); + mAppsCustomizeContent.removeApps(packageNames); } // Notify the drag controller - mDragController.onAppsRemoved(apps, this); + mDragController.onAppsRemoved(packageNames, this); } /** @@ -3532,7 +3578,7 @@ public final class Launcher extends Activity */ public void bindPackagesUpdated() { if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.onPackagesUpdated(false); + mAppsCustomizeContent.onPackagesUpdated(); } } @@ -3569,8 +3615,7 @@ public final class Launcher extends Activity } public boolean isRotationEnabled() { - boolean forceEnableRotation = "true".equalsIgnoreCase(SystemProperties.get( - FORCE_ENABLE_ROTATION_PROPERTY, "false")); + boolean forceEnableRotation = doesFileExist(FORCE_ENABLE_ROTATION_PROPERTY); boolean enableRotation = forceEnableRotation || getResources().getBoolean(R.bool.allow_rotation); return enableRotation; @@ -3608,7 +3653,6 @@ public final class Launcher extends Activity cling.init(this, positionData); cling.setVisibility(View.VISIBLE); cling.setLayerType(View.LAYER_TYPE_HARDWARE, null); - cling.requestAccessibilityFocus(); if (animate) { cling.buildLayer(); cling.setAlpha(0f); @@ -3626,7 +3670,7 @@ public final class Launcher extends Activity } private void dismissCling(final Cling cling, final String flag, int duration) { if (cling != null) { - ObjectAnimator anim = ObjectAnimator.ofFloat(cling, "alpha", 0f); + ObjectAnimator anim = LauncherAnimUtils.ofFloat(cling, "alpha", 0f); anim.setDuration(duration); anim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { @@ -3746,6 +3790,17 @@ public final class Launcher extends Activity writer.println(" " + sDumpLogs.get(i)); } } + + public static void dumpDebugLogsToConsole() { + Log.d(TAG, ""); + Log.d(TAG, "*********************"); + Log.d(TAG, "Launcher debug logs: "); + for (int i = 0; i < sDumpLogs.size(); i++) { + Log.d(TAG, " " + sDumpLogs.get(i)); + } + Log.d(TAG, "*********************"); + Log.d(TAG, ""); + } } interface LauncherTransitionable { diff --git a/src/com/android/launcher2/LauncherAnimUtils.java b/src/com/android/launcher2/LauncherAnimUtils.java new file mode 100644 index 000000000..9317c31b6 --- /dev/null +++ b/src/com/android/launcher2/LauncherAnimUtils.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 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.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; + +import java.util.HashSet; + +public class LauncherAnimUtils { + static HashSet<Animator> sAnimators = new HashSet<Animator>(); + static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() { + public void onAnimationStart(Animator animation) { + } + + public void onAnimationRepeat(Animator animation) { + } + + public void onAnimationEnd(Animator animation) { + sAnimators.remove(animation); + } + + public void onAnimationCancel(Animator animation) { + sAnimators.remove(animation); + } + }; + + public static void cancelOnDestroyActivity(Animator a) { + sAnimators.add(a); + a.addListener(sEndAnimListener); + } + + public static void onDestroyActivity() { + HashSet<Animator> animators = new HashSet<Animator>(sAnimators); + for (Animator a : animators) { + if (a.isRunning()) { + a.cancel(); + } else { + sAnimators.remove(a); + } + } + } + + public static AnimatorSet createAnimatorSet() { + AnimatorSet anim = new AnimatorSet(); + cancelOnDestroyActivity(anim); + return anim; + } + + public static ValueAnimator ofFloat(float... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setFloatValues(values); + cancelOnDestroyActivity(anim); + return anim; + } + + public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { + ObjectAnimator anim = new ObjectAnimator(); + anim.setTarget(target); + anim.setPropertyName(propertyName); + anim.setFloatValues(values); + cancelOnDestroyActivity(anim); + return anim; + } + + public static ObjectAnimator ofPropertyValuesHolder(Object target, + PropertyValuesHolder... values) { + ObjectAnimator anim = new ObjectAnimator(); + anim.setTarget(target); + anim.setValues(values); + cancelOnDestroyActivity(anim); + return anim; + } +} diff --git a/src/com/android/launcher2/LauncherAppWidgetHost.java b/src/com/android/launcher2/LauncherAppWidgetHost.java index 68d4903da..45c1d2311 100644 --- a/src/com/android/launcher2/LauncherAppWidgetHost.java +++ b/src/com/android/launcher2/LauncherAppWidgetHost.java @@ -27,8 +27,12 @@ import android.content.Context; * always pick up and move widgets. */ public class LauncherAppWidgetHost extends AppWidgetHost { - public LauncherAppWidgetHost(Context context, int hostId) { - super(context, hostId); + + Launcher mLauncher; + + public LauncherAppWidgetHost(Launcher launcher, int hostId) { + super(launcher, hostId); + mLauncher = launcher; } @Override @@ -42,4 +46,10 @@ public class LauncherAppWidgetHost extends AppWidgetHost { super.stopListening(); clearViews(); } + + protected void onProvidersChanged() { + // Once we get the message that widget packages are updated, we need to rebind items + // in AppsCustomize accordingly. + mLauncher.bindPackagesUpdated(); + } } diff --git a/src/com/android/launcher2/LauncherAppWidgetHostView.java b/src/com/android/launcher2/LauncherAppWidgetHostView.java index 9970c7675..549d3340e 100644 --- a/src/com/android/launcher2/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher2/LauncherAppWidgetHostView.java @@ -18,9 +18,6 @@ package com.android.launcher2; import android.appwidget.AppWidgetHostView; import android.content.Context; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.Parcel; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index 92be7e4df..792759399 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -103,7 +103,7 @@ public class LauncherModel extends BroadcastReceiver { private WeakReference<Callbacks> mCallbacks; // < only access in worker thread > - private AllAppsList mAllAppsList; + private AllAppsList mBgAllAppsList; // The lock that must be acquired before referencing any static bg data structures. Unlike // other locks, this one can generally be held long-term because we never expect any of these @@ -115,9 +115,9 @@ public class LauncherModel extends BroadcastReceiver { // LauncherModel to their ids static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>(); - // sBgItems is passed to bindItems, which expects a list of all folders and shortcuts created by - // LauncherModel that are directly on the home screen (however, no widgets or shortcuts - // within folders). + // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts + // created by LauncherModel that are directly on the home screen (however, no widgets or + // shortcuts within folders). static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>(); // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget() @@ -129,7 +129,6 @@ public class LauncherModel extends BroadcastReceiver { // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>(); - // </ only access in worker thread > private IconCache mIconCache; @@ -151,7 +150,7 @@ public class LauncherModel extends BroadcastReceiver { public void bindAllApplications(ArrayList<ApplicationInfo> apps); public void bindAppsAdded(ArrayList<ApplicationInfo> apps); public void bindAppsUpdated(ArrayList<ApplicationInfo> apps); - public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent); + public void bindAppsRemoved(ArrayList<String> packageNames, boolean permanent); public void bindPackagesUpdated(); public boolean isAllAppsVisible(); public boolean isAllAppsButtonRank(int rank); @@ -162,7 +161,7 @@ public class LauncherModel extends BroadcastReceiver { LauncherModel(LauncherApplication app, IconCache iconCache) { mAppsCanBeOnExternalStorage = !Environment.isExternalStorageEmulated(); mApp = app; - mAllAppsList = new AllAppsList(iconCache); + mBgAllAppsList = new AllAppsList(iconCache); mIconCache = iconCache; mDefaultIcon = Utilities.createIconBitmap( @@ -249,12 +248,38 @@ public class LauncherModel extends BroadcastReceiver { } } + static void checkItemInfo(final ItemInfo item) { + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); + final long itemId = item.id; + Runnable r = new Runnable() { + public void run() { + synchronized (sBgLock) { + ItemInfo modelItem = sBgItemsIdMap.get(itemId); + if (modelItem != null && item != modelItem) { + // the modelItem needs to match up perfectly with item if our model is + // to be consistent with the database-- for now, just require + // modelItem == item + String msg = "item: " + ((item != null) ? item.toString() : "null") + + "modelItem: " + + ((modelItem != null) ? modelItem.toString() : "null") + + "Error: ItemInfo passed to checkItemInfo doesn't match original"; + RuntimeException e = new RuntimeException(msg); + e.setStackTrace(stackTrace); + throw e; + } + } + } + }; + runOnWorkerThread(r); + } + static void updateItemInDatabaseHelper(Context context, final ContentValues values, final ItemInfo item, final String callingFunction) { final long itemId = item.id; final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false); final ContentResolver cr = context.getContentResolver(); + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); Runnable r = new Runnable() { public void run() { cr.update(uri, values, null, null); @@ -272,14 +297,36 @@ public class LauncherModel extends BroadcastReceiver { throw new RuntimeException(msg); } + if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP && + item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + // Item is in a folder, make sure this folder exists + if (!sBgFolders.containsKey(item.container)) { + // An items container is being set to a that of an item which is not in + // the list of Folders. + String msg = "item: " + item + " container being set to: " + + item.container + ", not in the list of folders"; + RuntimeException e = new RuntimeException(msg); + e.setStackTrace(stackTrace); + Launcher.dumpDebugLogsToConsole(); + throw e; + } + } + // Items are added/removed from the corresponding FolderInfo elsewhere, such // as in Workspace.onDrop. Here, we just add/remove them from the list of items // that are on the desktop, as appropriate if (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP || modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - if (!sBgWorkspaceItems.contains(modelItem)) { - sBgWorkspaceItems.add(modelItem); - + switch (modelItem.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: + if (!sBgWorkspaceItems.contains(modelItem)) { + sBgWorkspaceItems.add(modelItem); + } + break; + default: + break; } } else { sBgWorkspaceItems.remove(modelItem); @@ -295,6 +342,11 @@ public class LauncherModel extends BroadcastReceiver { */ static void moveItemInDatabase(Context context, final ItemInfo item, final long container, final int screen, final int cellX, final int cellY) { + String transaction = "DbDebug Modify item (" + item.title + ") in db, id: " + item.id + + " (" + item.container + ", " + item.screen + ", " + item.cellX + ", " + item.cellY + + ") --> " + "(" + container + ", " + screen + ", " + cellX + ", " + cellY + ")"; + Launcher.sDumpLogs.add(transaction); + Log.d(TAG, transaction); item.container = container; item.cellX = cellX; item.cellY = cellY; @@ -322,7 +374,11 @@ public class LauncherModel extends BroadcastReceiver { */ static void modifyItemInDatabase(Context context, final ItemInfo item, final long container, final int screen, final int cellX, final int cellY, final int spanX, final int spanY) { - item.container = container; + String transaction = "DbDebug Modify item (" + item.title + ") in db, id: " + item.id + + " (" + item.container + ", " + item.screen + ", " + item.cellX + ", " + item.cellY + + ") --> " + "(" + container + ", " + screen + ", " + cellX + ", " + cellY + ")"; + Launcher.sDumpLogs.add(transaction); + Log.d(TAG, transaction); item.cellX = cellX; item.cellY = cellY; item.spanX = spanX; @@ -345,7 +401,7 @@ public class LauncherModel extends BroadcastReceiver { values.put(LauncherSettings.Favorites.SPANY, item.spanY); values.put(LauncherSettings.Favorites.SCREEN, item.screen); - updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase"); + updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase"); } /** @@ -487,10 +543,19 @@ public class LauncherModel extends BroadcastReceiver { values.put(LauncherSettings.Favorites._ID, item.id); item.updateValuesWithCoordinates(values, item.cellX, item.cellY); + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); + Runnable r = new Runnable() { public void run() { + String transaction = "DbDebug Add item (" + item.title + ") to db, id: " + + item.id + " (" + container + ", " + screen + ", " + cellX + ", " + + cellY + ")"; + Launcher.sDumpLogs.add(transaction); + Log.d(TAG, transaction); + cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI : LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values); + // Lock on mBgLock *after* the db operation synchronized (sBgLock) { if (sBgItemsIdMap.containsKey(item.id)) { @@ -508,6 +573,16 @@ public class LauncherModel extends BroadcastReceiver { if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP || item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { sBgWorkspaceItems.add(item); + } else { + if (!sBgFolders.containsKey(item.container)) { + // Adding an item to a folder that doesn't exist. + String msg = "adding item: " + item + " to a folder that " + + " doesn't exist"; + RuntimeException e = new RuntimeException(msg); + e.setStackTrace(stackTrace); + Launcher.dumpDebugLogsToConsole(); + throw e; + } } break; case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: @@ -554,14 +629,35 @@ public class LauncherModel extends BroadcastReceiver { static void deleteItemFromDatabase(Context context, final ItemInfo item) { final ContentResolver cr = context.getContentResolver(); final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false); + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); + Runnable r = new Runnable() { public void run() { + String transaction = "DbDebug Delete item (" + item.title + ") from db, id: " + + item.id + " (" + item.container + ", " + item.screen + ", " + item.cellX + + ", " + item.cellY + ")"; + Launcher.sDumpLogs.add(transaction); + Log.d(TAG, transaction); + cr.delete(uriToDelete, null, null); + // Lock on mBgLock *after* the db operation synchronized (sBgLock) { switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: sBgFolders.remove(item.id); + for (ItemInfo info: sBgItemsIdMap.values()) { + if (info.container == item.id) { + // We are deleting a folder which still contains items that + // think they are contained by that folder. + String msg = "deleting a folder (" + item + ") which still " + + "contains items (" + info + ")"; + RuntimeException e = new RuntimeException(msg); + e.setStackTrace(stackTrace); + Launcher.dumpDebugLogsToConsole(); + throw e; + } + } sBgWorkspaceItems.remove(item); break; case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: @@ -1685,7 +1781,7 @@ public class LauncherModel extends BroadcastReceiver { // shallow copy @SuppressWarnings("unchecked") final ArrayList<ApplicationInfo> list - = (ArrayList<ApplicationInfo>) mAllAppsList.data.clone(); + = (ArrayList<ApplicationInfo>) mBgAllAppsList.data.clone(); Runnable r = new Runnable() { public void run() { final long t = SystemClock.uptimeMillis(); @@ -1732,7 +1828,7 @@ public class LauncherModel extends BroadcastReceiver { int batchSize = -1; while (i < N && !mStopped) { if (i == 0) { - mAllAppsList.clear(); + mBgAllAppsList.clear(); final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; apps = packageManager.queryIntentActivities(mainIntent, 0); if (DEBUG_LOADERS) { @@ -1770,15 +1866,15 @@ public class LauncherModel extends BroadcastReceiver { startIndex = i; for (int j=0; i<N && j<batchSize; j++) { // This builds the icon bitmaps. - mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i), + mBgAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i), mIconCache, mLabelCache)); i++; } final boolean first = i <= batchSize; final Callbacks callbacks = tryGetCallbacks(oldCallbacks); - final ArrayList<ApplicationInfo> added = mAllAppsList.added; - mAllAppsList.added = new ArrayList<ApplicationInfo>(); + final ArrayList<ApplicationInfo> added = mBgAllAppsList.added; + mBgAllAppsList.added = new ArrayList<ApplicationInfo>(); mHandler.post(new Runnable() { public void run() { @@ -1861,42 +1957,45 @@ public class LauncherModel extends BroadcastReceiver { case OP_ADD: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]); - mAllAppsList.addPackage(context, packages[i]); + mBgAllAppsList.addPackage(context, packages[i]); } break; case OP_UPDATE: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]); - mAllAppsList.updatePackage(context, packages[i]); + mBgAllAppsList.updatePackage(context, packages[i]); } break; case OP_REMOVE: case OP_UNAVAILABLE: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]); - mAllAppsList.removePackage(packages[i]); + mBgAllAppsList.removePackage(packages[i]); } break; } ArrayList<ApplicationInfo> added = null; - ArrayList<ApplicationInfo> removed = null; ArrayList<ApplicationInfo> modified = null; - if (mAllAppsList.added.size() > 0) { - added = mAllAppsList.added; - mAllAppsList.added = new ArrayList<ApplicationInfo>(); + if (mBgAllAppsList.added.size() > 0) { + added = new ArrayList<ApplicationInfo>(mBgAllAppsList.added); + mBgAllAppsList.added.clear(); } - if (mAllAppsList.removed.size() > 0) { - removed = mAllAppsList.removed; - mAllAppsList.removed = new ArrayList<ApplicationInfo>(); - for (ApplicationInfo info: removed) { - mIconCache.remove(info.intent.getComponent()); - } + if (mBgAllAppsList.modified.size() > 0) { + modified = new ArrayList<ApplicationInfo>(mBgAllAppsList.modified); + mBgAllAppsList.modified.clear(); } - if (mAllAppsList.modified.size() > 0) { - modified = mAllAppsList.modified; - mAllAppsList.modified = new ArrayList<ApplicationInfo>(); + // We may be removing packages that have no associated launcher application, so we + // pass through the removed package names directly. + // NOTE: We flush the icon cache aggressively in removePackage() above. + final ArrayList<String> removedPackageNames = new ArrayList<String>(); + if (mBgAllAppsList.removed.size() > 0) { + mBgAllAppsList.removed.clear(); + + for (int i = 0; i < N; ++i) { + removedPackageNames.add(packages[i]); + } } final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; @@ -1927,14 +2026,13 @@ public class LauncherModel extends BroadcastReceiver { } }); } - if (removed != null) { + if (!removedPackageNames.isEmpty()) { final boolean permanent = mOp != OP_UNAVAILABLE; - final ArrayList<ApplicationInfo> removedFinal = removed; mHandler.post(new Runnable() { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; if (callbacks == cb && cb != null) { - callbacks.bindAppsRemoved(removedFinal, permanent); + callbacks.bindAppsRemoved(removedPackageNames, permanent); } } }); @@ -1953,26 +2051,6 @@ public class LauncherModel extends BroadcastReceiver { } /** - * Returns all the Workspace ShortcutInfos associated with a particular package. - * @param intent - * @return - */ - ArrayList<ShortcutInfo> getShortcutInfosForPackage(String packageName) { - ArrayList<ShortcutInfo> infos = new ArrayList<ShortcutInfo>(); - synchronized (sBgLock) { - for (ItemInfo i : sBgWorkspaceItems) { - if (i instanceof ShortcutInfo) { - ShortcutInfo info = (ShortcutInfo) i; - if (packageName.equals(info.getPackageName())) { - infos.add(info); - } - } - } - } - return infos; - } - - /** * This is called from the code that adds shortcuts from the intent receiver. This * doesn't have a Cursor, but */ @@ -2422,10 +2500,10 @@ public class LauncherModel extends BroadcastReceiver { public void dumpState() { Log.d(TAG, "mCallbacks=" + mCallbacks); - ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mAllAppsList.data); - ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mAllAppsList.added); - ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mAllAppsList.removed); - ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mAllAppsList.modified); + ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data); + ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added); + ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed); + ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified); if (mLoaderTask != null) { mLoaderTask.dumpState(); } else { diff --git a/src/com/android/launcher2/LauncherProvider.java b/src/com/android/launcher2/LauncherProvider.java index 0720259f4..ccc126a11 100644 --- a/src/com/android/launcher2/LauncherProvider.java +++ b/src/com/android/launcher2/LauncherProvider.java @@ -751,12 +751,12 @@ public class LauncherProvider extends ContentProvider { private static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException { int type; - while ((type = parser.next()) != parser.START_TAG - && type != parser.END_DOCUMENT) { + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { ; } - if (type != parser.START_TAG) { + if (type != XmlPullParser.START_TAG) { throw new XmlPullParserException("No start tag found"); } diff --git a/src/com/android/launcher2/LauncherViewPropertyAnimator.java b/src/com/android/launcher2/LauncherViewPropertyAnimator.java index 88b4cb4b8..3ffc418ae 100644 --- a/src/com/android/launcher2/LauncherViewPropertyAnimator.java +++ b/src/com/android/launcher2/LauncherViewPropertyAnimator.java @@ -215,6 +215,7 @@ public class LauncherViewPropertyAnimator extends Animator implements AnimatorLi } mViewPropertyAnimator.setListener(this); mViewPropertyAnimator.start(); + LauncherAnimUtils.cancelOnDestroyActivity(this); } public LauncherViewPropertyAnimator translationX(float value) { diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java index ad0baf44d..4765dae02 100644 --- a/src/com/android/launcher2/PagedView.java +++ b/src/com/android/launcher2/PagedView.java @@ -18,7 +18,6 @@ package com.android.launcher2; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; @@ -791,20 +790,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(), getScrollY() + getBottom() - getTop()); - // On certain graphics drivers, if you draw to a off-screen buffer that's not - // used, it can lead to poor performance. We were running into this when - // setChildrenLayersEnabled was called on a CellLayout; that triggered a re-draw - // of that CellLayout's hardware layer, even if that CellLayout wasn't visible. - // As a fix, below we set pages that aren't going to be rendered are to be - // View.INVISIBLE, preventing re-drawing of their hardware layer for (int i = getChildCount() - 1; i >= 0; i--) { final View v = getPageAt(i); if (mForceDrawAllChildrenNextFrame || (leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) { - v.setVisibility(VISIBLE); drawChild(canvas, v, drawingTime); - } else { - v.setVisibility(INVISIBLE); } } mForceDrawAllChildrenNextFrame = false; @@ -1756,7 +1746,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (immediately) { mScrollIndicator.setAlpha(1f); } else { - mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 1f); + mScrollIndicatorAnimator = LauncherAnimUtils.ofFloat(mScrollIndicator, "alpha", 1f); mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeInDuration); mScrollIndicatorAnimator.start(); } @@ -1782,7 +1772,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mScrollIndicator.setVisibility(View.INVISIBLE); mScrollIndicator.setAlpha(0f); } else { - mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 0f); + mScrollIndicatorAnimator = LauncherAnimUtils.ofFloat(mScrollIndicator, "alpha", 0f); mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeOutDuration); mScrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() { private boolean cancelled = false; diff --git a/src/com/android/launcher2/PagedViewWidgetImageView.java b/src/com/android/launcher2/PagedViewWidgetImageView.java index 22db0abd8..992817786 100644 --- a/src/com/android/launcher2/PagedViewWidgetImageView.java +++ b/src/com/android/launcher2/PagedViewWidgetImageView.java @@ -18,12 +18,9 @@ package com.android.launcher2; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Insets; import android.util.AttributeSet; import android.widget.ImageView; - - class PagedViewWidgetImageView extends ImageView { public boolean mAllowRequestLayout = true; @@ -39,16 +36,11 @@ class PagedViewWidgetImageView extends ImageView { @Override protected void onDraw(Canvas canvas) { - - Insets insets = Insets.NONE; - if (getBackground() != null) { - insets = getBackground().getLayoutInsets(); - } canvas.save(); - canvas.clipRect(getScrollX() + getPaddingLeft() + insets.left, - getScrollY() + getPaddingTop() + insets.top, - getScrollX() + getRight() - getLeft() - getPaddingRight() - insets.right, - getScrollY() + getBottom() - getTop() - getPaddingBottom() - insets.bottom); + canvas.clipRect(getScrollX() + getPaddingLeft(), + getScrollY() + getPaddingTop(), + getScrollX() + getRight() - getLeft() - getPaddingRight(), + getScrollY() + getBottom() - getTop() - getPaddingBottom()); super.onDraw(canvas); canvas.restore(); diff --git a/src/com/android/launcher2/PreloadReceiver.java b/src/com/android/launcher2/PreloadReceiver.java index d1bc6393d..7bec72117 100644 --- a/src/com/android/launcher2/PreloadReceiver.java +++ b/src/com/android/launcher2/PreloadReceiver.java @@ -19,7 +19,6 @@ package com.android.launcher2; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.util.Log; public class PreloadReceiver extends BroadcastReceiver { @Override diff --git a/src/com/android/launcher2/RocketLauncher.java b/src/com/android/launcher2/RocketLauncher.java index 268769d2f..6eefedd03 100644 --- a/src/com/android/launcher2/RocketLauncher.java +++ b/src/com/android/launcher2/RocketLauncher.java @@ -21,7 +21,6 @@ package com.android.launcher2; import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.TimeAnimator; import android.content.ComponentName; import android.content.Context; @@ -150,11 +149,11 @@ public class RocketLauncher extends BasicDream { } }, LAUNCH_ZOOM_TIME); endscale = 0; - AnimatorSet s = new AnimatorSet(); + AnimatorSet s = LauncherAnimUtils.createAnimatorSet(); s.playTogether( - ObjectAnimator.ofFloat(this, "scaleX", 15f), - ObjectAnimator.ofFloat(this, "scaleY", 15f), - ObjectAnimator.ofFloat(this, "alpha", 0f) + LauncherAnimUtils.ofFloat(this, "scaleX", 15f), + LauncherAnimUtils.ofFloat(this, "scaleY", 15f), + LauncherAnimUtils.ofFloat(this, "alpha", 0f) ); // make sure things are still moving until the very last instant the diff --git a/src/com/android/launcher2/SearchDropTargetBar.java b/src/com/android/launcher2/SearchDropTargetBar.java index a1d36cdfa..fada48a25 100644 --- a/src/com/android/launcher2/SearchDropTargetBar.java +++ b/src/com/android/launcher2/SearchDropTargetBar.java @@ -111,14 +111,14 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D // Create the various fade animations if (mEnableDropDownDropTargets) { mDropTargetBar.setTranslationY(-mBarHeight); - mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "translationY", + mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "translationY", -mBarHeight, 0f); - mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "translationY", 0, + mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "translationY", 0, -mBarHeight); } else { mDropTargetBar.setAlpha(0f); - mDropTargetBarAnim = ObjectAnimator.ofFloat(mDropTargetBar, "alpha", 0f, 1f); - mQSBSearchBarAnim = ObjectAnimator.ofFloat(mQSBSearchBar, "alpha", 1f, 0f); + mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f); + mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f); } setupAnimation(mDropTargetBarAnim, mDropTargetBar); setupAnimation(mQSBSearchBarAnim, mQSBSearchBar); @@ -224,16 +224,14 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D public Rect getSearchBarBounds() { if (mQSBSearchBar != null) { - final float appScale = mQSBSearchBar.getContext().getResources() - .getCompatibilityInfo().applicationScale; final int[] pos = new int[2]; mQSBSearchBar.getLocationOnScreen(pos); final Rect rect = new Rect(); - rect.left = (int) (pos[0] * appScale + 0.5f); - rect.top = (int) (pos[1] * appScale + 0.5f); - rect.right = (int) ((pos[0] + mQSBSearchBar.getWidth()) * appScale + 0.5f); - rect.bottom = (int) ((pos[1] + mQSBSearchBar.getHeight()) * appScale + 0.5f); + rect.left = pos[0]; + rect.top = pos[1]; + rect.right = pos[0] + mQSBSearchBar.getWidth(); + rect.bottom = pos[1] + mQSBSearchBar.getHeight(); return rect; } else { return null; diff --git a/src/com/android/launcher2/ShortcutAndWidgetContainer.java b/src/com/android/launcher2/ShortcutAndWidgetContainer.java index 8bebdcd45..8daf3954d 100644 --- a/src/com/android/launcher2/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher2/ShortcutAndWidgetContainer.java @@ -44,10 +44,6 @@ public class ShortcutAndWidgetContainer extends ViewGroup { mWallpaperManager = WallpaperManager.getInstance(context); } - public void enableHardwareLayers() { - setLayerType(LAYER_TYPE_HARDWARE, null); - } - public void setCellDimensions(int cellWidth, int cellHeight, int widthGap, int heightGap ) { mCellWidth = cellWidth; mCellHeight = cellHeight; diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java index 533059f57..968d3b836 100644 --- a/src/com/android/launcher2/ShortcutInfo.java +++ b/src/com/android/launcher2/ShortcutInfo.java @@ -30,11 +30,6 @@ import android.util.Log; class ShortcutInfo extends ItemInfo { /** - * The application name. - */ - CharSequence title; - - /** * The intent used to start the application. */ Intent intent; @@ -158,7 +153,7 @@ class ShortcutInfo extends ItemInfo { return "ShortcutInfo(title=" + title.toString() + "intent=" + intent + "id=" + this.id + " type=" + this.itemType + " container=" + this.container + " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY - + " isGesture=" + isGesture + " dropPos=" + dropPos + ")"; + + " dropPos=" + dropPos + ")"; } public static void dumpShortcutInfoList(String tag, String label, diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java index b27f7bb11..d3e451642 100644 --- a/src/com/android/launcher2/Utilities.java +++ b/src/com/android/launcher2/Utilities.java @@ -29,7 +29,6 @@ import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.TableMaskFilter; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; @@ -243,9 +242,7 @@ final class Utilities { sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL)); sGlowColorPressedPaint.setColor(0xffffc300); - sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); sGlowColorFocusedPaint.setColor(0xffff8e00); - sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); ColorMatrix cm = new ColorMatrix(); cm.setSaturation(0.2f); diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 44b9f68da..d1d47f5f6 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -24,7 +24,6 @@ import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.app.WallpaperManager; import android.appwidget.AppWidgetHostView; -import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; @@ -33,10 +32,8 @@ import android.content.SharedPreferences; 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.Point; import android.graphics.PointF; import android.graphics.Rect; @@ -45,7 +42,6 @@ import android.graphics.drawable.Drawable; import android.os.IBinder; import android.os.Parcelable; import android.util.AttributeSet; -import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseArray; import android.view.Display; @@ -175,16 +171,12 @@ public class Workspace extends SmoothPagedView private Bitmap mDragOutline = null; private final Rect mTempRect = new Rect(); private final int[] mTempXY = new int[2]; + private int[] mTempVisiblePagesRange = new int[2]; private float mOverscrollFade = 0; private boolean mOverscrollTransformsSet; public static final int DRAG_BITMAP_PADDING = 2; private boolean mWorkspaceFadeInAdjacentScreens; - // 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; @@ -285,6 +277,7 @@ public class Workspace extends SmoothPagedView // With workspace, data is available straight from the get-go setDataIsReady(); + mLauncher = (Launcher) context; final Resources res = getResources(); mWorkspaceFadeInAdjacentScreens = res.getBoolean(R.bool.config_workspaceFadeAdjacentScreens); mFadeInAdjacentScreens = false; @@ -303,20 +296,20 @@ public class Workspace extends SmoothPagedView // landscape TypedArray actionBarSizeTypedArray = context.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize }); - DisplayMetrics displayMetrics = res.getDisplayMetrics(); final float actionBarHeight = actionBarSizeTypedArray.getDimension(0, 0f); - final float systemBarHeight = res.getDimension(R.dimen.status_bar_height); - final float smallestScreenDim = res.getConfiguration().smallestScreenWidthDp * - displayMetrics.density; + + Point minDims = new Point(); + Point maxDims = new Point(); + mLauncher.getWindowManager().getDefaultDisplay().getCurrentSizeRange(minDims, maxDims); cellCountX = 1; - while (CellLayout.widthInPortrait(res, cellCountX + 1) <= smallestScreenDim) { + while (CellLayout.widthInPortrait(res, cellCountX + 1) <= minDims.x) { cellCountX++; } cellCountY = 1; while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1) - <= smallestScreenDim - systemBarHeight) { + <= minDims.y) { cellCountY++; } } @@ -338,7 +331,6 @@ public class Workspace extends SmoothPagedView LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY); setHapticFeedbackEnabled(false); - mLauncher = (Launcher) context; initWorkspace(); // Disable multitouch across the workspace/all apps/customize tray @@ -378,19 +370,9 @@ public class Workspace extends SmoothPagedView return r; } - public void buildPageHardwareLayers() { - if (getWindowToken() != null) { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - CellLayout cl = (CellLayout) getChildAt(i); - cl.getShortcutsAndWidgets().buildLayer(); - } - } - } - public void onDragStart(DragSource source, Object info, int dragAction) { mIsDragOccuring = true; - updateChildrenLayersEnabled(); + updateChildrenLayersEnabled(false); mLauncher.lockScreenOrientation(); setChildrenBackgroundAlphaMultipliers(1f); // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging @@ -400,7 +382,7 @@ public class Workspace extends SmoothPagedView public void onDragEnd() { mIsDragOccuring = false; - updateChildrenLayersEnabled(); + updateChildrenLayersEnabled(false); mLauncher.unlockScreenOrientation(false); // Re-enable any Un/InstallShortcutReceiver and now process any queued items @@ -450,7 +432,6 @@ public class Workspace extends SmoothPagedView CellLayout cl = ((CellLayout) child); cl.setOnInterceptTouchListener(this); cl.setClickable(true); - cl.enableHardwareLayers(); cl.setContentDescription(getContext().getString( R.string.workspace_description_format, getChildCount())); } @@ -733,16 +714,11 @@ public class Workspace extends SmoothPagedView } } - @Override - protected boolean isScrollingIndicatorEnabled() { - return super.isScrollingIndicatorEnabled() && (mState != State.SPRING_LOADED); - } - protected void onPageBeginMoving() { super.onPageBeginMoving(); if (isHardwareAccelerated()) { - updateChildrenLayersEnabled(); + updateChildrenLayersEnabled(false); } else { if (mNextPage != INVALID_PAGE) { // we're snapping to a particular screen @@ -776,7 +752,7 @@ public class Workspace extends SmoothPagedView super.onPageEndMoving(); if (isHardwareAccelerated()) { - updateChildrenLayersEnabled(); + updateChildrenLayersEnabled(false); } else { clearChildrenCache(); } @@ -851,10 +827,12 @@ public class Workspace extends SmoothPagedView } protected void setWallpaperDimension() { - DisplayMetrics displayMetrics = new DisplayMetrics(); - mLauncher.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); - final int maxDim = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels); - final int minDim = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels); + Point minDims = new Point(); + Point maxDims = new Point(); + mLauncher.getWindowManager().getDefaultDisplay().getCurrentSizeRange(minDims, maxDims); + + final int maxDim = Math.max(maxDims.x, maxDims.y); + final int minDim = Math.min(minDims.x, minDims.y); // We need to ensure that there is enough extra space in the wallpaper for the intended // parallax effects @@ -1102,7 +1080,7 @@ public class Workspace extends SmoothPagedView if (!isSmall() && !mIsSwitchingState) { if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel(); if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel(); - mChildrenOutlineFadeInAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 1.0f); + mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f); mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION); mChildrenOutlineFadeInAnimation.start(); } @@ -1112,7 +1090,7 @@ public class Workspace extends SmoothPagedView if (!isSmall() && !mIsSwitchingState) { if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel(); if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel(); - mChildrenOutlineFadeOutAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 0.0f); + mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f); mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION); mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY); mChildrenOutlineFadeOutAnimation.start(); @@ -1157,7 +1135,7 @@ public class Workspace extends SmoothPagedView float startAlpha = getBackgroundAlpha(); if (finalAlpha != startAlpha) { if (animated) { - mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(startAlpha, finalAlpha); + mBackgroundFadeOutAnimation = LauncherAnimUtils.ofFloat(startAlpha, finalAlpha); mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue()); @@ -1183,31 +1161,6 @@ public class Workspace extends SmoothPagedView 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; @@ -1267,6 +1220,7 @@ public class Workspace extends SmoothPagedView super.screenScrolled(screenCenter); updatePageAlphaValues(screenCenter); + enableHwLayersOnVisiblePages(); if (mOverScrollX < 0 || mOverScrollX > mMaxScrollX) { int index = mOverScrollX < 0 ? 0 : getChildCount() - 1; @@ -1415,18 +1369,66 @@ public class Workspace extends SmoothPagedView } } - private void updateChildrenLayersEnabled() { + + private void updateChildrenLayersEnabled(boolean force) { boolean small = mState == State.SMALL || mIsSwitchingState; - boolean enableChildrenLayers = small || mAnimatingViewIntoPlace || isPageMoving(); + boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving(); if (enableChildrenLayers != mChildrenLayersEnabled) { mChildrenLayersEnabled = enableChildrenLayers; - for (int i = 0; i < getPageCount(); i++) { - ((ViewGroup)getChildAt(i)).setChildrenLayersEnabled(mChildrenLayersEnabled); + if (mChildrenLayersEnabled) { + enableHwLayersOnVisiblePages(); + } else { + for (int i = 0; i < getPageCount(); i++) { + final CellLayout cl = (CellLayout) getChildAt(i); + cl.disableHardwareLayers(); + } } } } + private void enableHwLayersOnVisiblePages() { + if (mChildrenLayersEnabled) { + final int screenCount = getChildCount(); + getVisiblePages(mTempVisiblePagesRange); + int leftScreen = mTempVisiblePagesRange[0]; + int rightScreen = mTempVisiblePagesRange[1]; + if (leftScreen == rightScreen) { + // make sure we're caching at least two pages always + if (rightScreen < screenCount - 1) { + rightScreen++; + } else if (leftScreen > 0) { + leftScreen--; + } + } + for (int i = 0; i < screenCount; i++) { + final CellLayout layout = (CellLayout) getChildAt(i); + if (!(leftScreen <= i && i <= rightScreen && shouldDrawChild(layout))) { + layout.disableHardwareLayers(); + } + } + for (int i = 0; i < screenCount; i++) { + final CellLayout layout = (CellLayout) getChildAt(i); + if (leftScreen <= i && i <= rightScreen && shouldDrawChild(layout)) { + layout.enableHardwareLayers(); + } + } + } + } + + public void buildPageHardwareLayers() { + // force layers to be enabled just for the call to buildLayer + updateChildrenLayersEnabled(true); + if (getWindowToken() != null) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + CellLayout cl = (CellLayout) getChildAt(i); + cl.buildHardwareLayer(); + } + } + updateChildrenLayersEnabled(false); + } + protected void onWallpaperTap(MotionEvent ev) { final int[] position = mTempCell; getLocationOnScreen(position); @@ -1515,14 +1517,14 @@ public class Workspace extends SmoothPagedView mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING); } - public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, Paint alphaClipPaint) { + public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) { final Canvas canvas = new Canvas(); int[] size = estimateItemSize(info.spanX, info.spanY, info, false); // The outline is used to visualize where the item will land if dropped mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0], - size[1], alphaClipPaint); + size[1], clipAlpha); } public void exitWidgetResizeMode() { @@ -1560,7 +1562,7 @@ public class Workspace extends SmoothPagedView // Initialize animation arrays for the first time if necessary initAnimationArrays(); - AnimatorSet anim = animated ? new AnimatorSet() : null; + AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null; // Stop any scrolling, move to the current page right away setCurrentPage(getNextPage()); @@ -1585,7 +1587,7 @@ public class Workspace extends SmoothPagedView if (oldStateIsNormal && stateIsSmall) { zoomIn = false; setLayoutScale(finalScaleFactor); - updateChildrenLayersEnabled(); + updateChildrenLayersEnabled(false); } else { finalBackgroundAlpha = 1.0f; setLayoutScale(finalScaleFactor); @@ -1676,7 +1678,7 @@ public class Workspace extends SmoothPagedView } if (mOldBackgroundAlphas[i] != 0 || mNewBackgroundAlphas[i] != 0) { - ValueAnimator bgAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration); + ValueAnimator bgAnim = LauncherAnimUtils.ofFloat(0f, 1f).setDuration(duration); bgAnim.setInterpolator(mZoomInInterpolator); bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() { public void onAnimationUpdate(float a, float b) { @@ -1725,7 +1727,7 @@ public class Workspace extends SmoothPagedView public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { mIsSwitchingState = false; mWallpaperOffset.setOverrideHorizontalCatchupConstant(false); - updateChildrenLayersEnabled(); + updateChildrenLayersEnabled(false); // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure // ensure that only the current page is visible during (and subsequently, after) the // transition animation. If fade adjacent pages is disabled, then re-enable the page @@ -1835,7 +1837,7 @@ public class Workspace extends SmoothPagedView * Responsibility for the bitmap is transferred to the caller. */ private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h, - Paint alphaClipPaint) { + boolean clipAlpha) { final int outlineColor = getResources().getColor(android.R.color.holo_blue_light); final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); canvas.setBitmap(b); @@ -1852,7 +1854,7 @@ public class Workspace extends SmoothPagedView canvas.drawBitmap(orig, src, dst, null); mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor, - alphaClipPaint); + clipAlpha); canvas.setBitmap(null); return b; @@ -2163,7 +2165,7 @@ public class Workspace extends SmoothPagedView // We want the point to be mapped to the dragTarget. if (dropTargetLayout != null) { if (mLauncher.isHotseatLayout(dropTargetLayout)) { - mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter); + mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter); } else { mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null); } @@ -2307,7 +2309,7 @@ public class Workspace extends SmoothPagedView @Override public void run() { mAnimatingViewIntoPlace = false; - updateChildrenLayersEnabled(); + updateChildrenLayersEnabled(false); if (finalResizeRunnable != null) { finalResizeRunnable.run(); } @@ -2430,7 +2432,13 @@ public class Workspace extends SmoothPagedView // Here we store the final page that will be dropped to, if the workspace in fact // receives the drop if (mInScrollArea) { - mDropToLayout = mDragOverlappingLayout; + if (isPageMoving()) { + // If the user drops while the page is scrolling, we should use that page as the + // destination instead of the page that is being hovered over. + mDropToLayout = (CellLayout) getPageAt(getNextPage()); + } else { + mDropToLayout = mDragOverlappingLayout; + } } else { mDropToLayout = mDragTargetLayout; } @@ -3330,7 +3338,7 @@ public class Workspace extends SmoothPagedView // hardware layers on children are enabled on startup, but should be disabled until // needed - updateChildrenLayersEnabled(); + updateChildrenLayersEnabled(false); setWallpaperDimension(); } @@ -3382,7 +3390,8 @@ public class Workspace extends SmoothPagedView View v = cl.getShortcutsAndWidgets().getChildAt(i); ItemInfo info = (ItemInfo) v.getTag(); // Null check required as the AllApps button doesn't have an item info - if (info != null) { + if (info != null && info.requiresDbUpdate) { + info.requiresDbUpdate = false; LauncherModel.modifyItemInDatabase(mLauncher, info, container, screen, info.cellX, info.cellY, info.spanX, info.spanY); } @@ -3610,14 +3619,9 @@ public class Workspace extends SmoothPagedView } } - void removeItems(final ArrayList<ApplicationInfo> apps) { - final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext()); - + void removeItems(final ArrayList<String> packages) { final HashSet<String> packageNames = new HashSet<String>(); - final int appCount = apps.size(); - for (int i = 0; i < appCount; i++) { - packageNames.add(apps.get(i).componentName.getPackageName()); - } + packageNames.addAll(packages); ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts(); for (final CellLayout layoutParent: cellLayouts) { @@ -3698,11 +3702,7 @@ public class Workspace extends SmoothPagedView }); } - // It is no longer the case the BubbleTextViews correspond 1:1 with the workspace items in - // the database (and LauncherModel) since shortcuts are not added and animated in until - // the user returns to launcher. As a result, we really should be cleaning up the Db - // regardless of whether the item was added or not (unlike the logic above). This is only - // relevant for direct workspace items. + // Clean up new-apps animation list post(new Runnable() { @Override public void run() { @@ -3712,26 +3712,18 @@ public class Workspace extends SmoothPagedView Set<String> newApps = sp.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, null); - for (String packageName: packageNames) { - // Remove all items that have the same package, but were not removed above - ArrayList<ShortcutInfo> infos = - mLauncher.getModel().getShortcutInfosForPackage(packageName); - for (ShortcutInfo info : infos) { - LauncherModel.deleteItemFromDatabase(mLauncher, info); - } - // Remove all queued items that match the same package - if (newApps != null) { - synchronized (newApps) { - Iterator<String> iter = newApps.iterator(); - while (iter.hasNext()) { - try { - Intent intent = Intent.parseUri(iter.next(), 0); - String pn = ItemInfo.getPackageName(intent); - if (packageNames.contains(pn)) { - iter.remove(); - } - } catch (URISyntaxException e) {} - } + // Remove all queued items that match the same package + if (newApps != null) { + synchronized (newApps) { + Iterator<String> iter = newApps.iterator(); + while (iter.hasNext()) { + try { + Intent intent = Intent.parseUri(iter.next(), 0); + String pn = ItemInfo.getPackageName(intent); + if (packageNames.contains(pn)) { + iter.remove(); + } + } catch (URISyntaxException e) {} } } } |