diff options
46 files changed, 1332 insertions, 2069 deletions
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml index b13984a26..d5dd91ab4 100644 --- a/res/layout-land/launcher.xml +++ b/res/layout-land/launcher.xml @@ -57,8 +57,8 @@ android:id="@+id/overview_panel" android:visibility="gone" /> - <include layout="@layout/apps_customize_pane" - android:id="@+id/apps_customize_pane" + <include layout="@layout/widgets_view" + android:id="@+id/widgets_view" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" /> diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml index 3cb338efe..5a018c516 100644 --- a/res/layout-port/launcher.xml +++ b/res/layout-port/launcher.xml @@ -66,8 +66,8 @@ android:id="@+id/search_drop_target_bar" layout="@layout/search_drop_target_bar" /> - <include layout="@layout/apps_customize_pane" - android:id="@+id/apps_customize_pane" + <include layout="@layout/widgets_view" + android:id="@+id/widgets_view" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" /> diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml index a3d502cf4..8bd827a25 100644 --- a/res/layout-sw720dp/launcher.xml +++ b/res/layout-sw720dp/launcher.xml @@ -66,8 +66,8 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> - <include layout="@layout/apps_customize_pane" - android:id="@+id/apps_customize_pane" + <include layout="@layout/widgets_view" + android:id="@+id/widget_view" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" /> diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml deleted file mode 100644 index e42576ffe..000000000 --- a/res/layout/apps_customize_pane.xml +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<com.android.launcher3.AppsCustomizeTabHost - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto" - android:clipChildren="false"> - - <LinearLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:clipChildren="false" - android:orientation="vertical"> - - <FrameLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:clipChildren="false"> - <FrameLayout - android:id="@+id/fake_page_container" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:clipChildren="false" - android:clipToPadding="false"> - <FrameLayout - android:id="@+id/fake_page" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="invisible" - android:clipToPadding="false" /> - </FrameLayout> - <com.android.launcher3.AppsCustomizePagedView - android:id="@+id/apps_customize_pane_content" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x" - launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y" - launcher:maxGap="@dimen/workspace_max_gap" - launcher:pageIndicator="@+id/apps_customize_page_indicator" /> - </FrameLayout> - <include - android:id="@+id/apps_customize_page_indicator" - layout="@layout/page_indicator" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center" /> - </LinearLayout> -</com.android.launcher3.AppsCustomizeTabHost> diff --git a/res/layout/apps_list_row_view.xml b/res/layout/apps_list_row_view.xml index 83c175bb8..e80285b95 100644 --- a/res/layout/apps_list_row_view.xml +++ b/res/layout/apps_list_row_view.xml @@ -30,4 +30,4 @@ android:textColor="@color/apps_view_section_text_color" android:textSize="@dimen/apps_view_section_text_size" android:focusable="false" /> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/res/layout/apps_customize_widget.xml b/res/layout/widget_cell.xml index a8344e3ff..1286a622b 100644 --- a/res/layout/apps_customize_widget.xml +++ b/res/layout/widget_cell.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project +<!-- Copyright (C) 2015 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,58 +13,26 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.launcher3.PagedViewWidget +<com.android.launcher3.widget.WidgetCell xmlns:android="http://schemas.android.com/apk/res/android" xmlns:launcher="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" - android:background="@drawable/focusable_view_bg" android:focusable="true"> <LinearLayout - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_weight="1"> - <FrameLayout - android:id="@+id/left_border" - android:layout_width="1dp" - android:layout_height="match_parent" - android:background="@color/widget_text_panel" - android:visibility="gone" /> - - <!-- The preview of the widget or shortcut. --> - <com.android.launcher3.PagedViewWidgetImageView - android:id="@+id/widget_preview" - style="@style/PagedViewWidgetImageView" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - android:paddingTop="@dimen/app_widget_preview_padding_top" - android:paddingEnd="@dimen/app_widget_preview_padding_right" - android:paddingRight="@dimen/app_widget_preview_padding_right" - android:scaleType="matrix" /> - <FrameLayout - android:id="@+id/right_border" - android:layout_width="1dp" - android:layout_height="match_parent" - android:background="@color/widget_text_panel" - android:visibility="gone" /> - </LinearLayout> - - <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="@dimen/app_widget_preview_label_vertical_padding" - android:paddingBottom="@dimen/app_widget_preview_label_vertical_padding" - android:paddingLeft="@dimen/app_widget_preview_label_horizontal_padding" - android:paddingRight="@dimen/app_widget_preview_label_horizontal_padding" - android:background="@color/widget_text_panel" + android:paddingTop="@dimen/widget_preview_label_vertical_padding" + android:paddingBottom="@dimen/widget_preview_label_vertical_padding" + android:paddingLeft="@dimen/widget_preview_label_horizontal_padding" + android:paddingRight="@dimen/widget_preview_label_horizontal_padding" android:orientation="horizontal"> + <!-- The name of the widget. --> <TextView android:id="@+id/widget_name" @@ -91,6 +59,7 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginStart="5dp" + android:layout_marginLeft="5dp" android:layout_weight="0" android:gravity="start" @@ -101,5 +70,16 @@ android:shadowColor="#B0000000" /> </LinearLayout> + <!-- The image of the widget. --> + <com.android.launcher3.widget.WidgetImageView + android:id="@+id/widget_preview" + style="@style/WidgetImageView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingTop="@dimen/widget_preview_padding_top" + android:paddingEnd="@dimen/widget_preview_padding_right" + android:paddingRight="@dimen/widget_preview_padding_right" + android:scaleType="matrix" /> -</com.android.launcher3.PagedViewWidget> +</com.android.launcher3.widget.WidgetCell> diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml new file mode 100644 index 000000000..c7863c7c3 --- /dev/null +++ b/res/layout/widgets_list_row_view.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/widgets_cell_list_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp" + android:focusable="true" + android:background="@drawable/focusable_view_bg" + android:descendantFocusability="afterDescendants"> + + <!-- Section info --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:focusable="true" + android:background="@drawable/focusable_view_bg" + android:descendantFocusability="afterDescendants"> + <ImageView + android:id="@+id/section_image" + android:layout_width="@dimen/widget_section_height" + android:layout_height="@dimen/widget_section_height" + android:paddingLeft="@dimen/widget_section_icon_padding" + android:paddingRight="@dimen/widget_section_icon_padding" + android:paddingTop="@dimen/widget_section_icon_padding" + android:paddingBottom="@dimen/widget_section_icon_padding" + android:background="@color/widget_text_panel" + /> + <TextView + android:id="@+id/section" + android:layout_width="match_parent" + android:layout_height="@dimen/widget_section_height" + android:paddingTop="8dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:gravity="start|center_vertical" + android:textColor="@color/widgets_view_section_text_color" + android:background="@color/widget_text_panel" + android:textSize="20sp" + android:focusable="false" /> + </LinearLayout> + + <!-- Widget list --> + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="end" + > + <!-- TODO(hyunyoungs): replace the indicator with actual assets. --> + <FrameLayout + android:id="@+id/scrollable_indicator" + android:layout_gravity="center_vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/ic_pageindicator_default" + android:visibility="invisible" + /> + <HorizontalScrollView + android:id="@+id/widgets_scroll_container" + android:layout_width="match_parent" + android:layout_height="@dimen/widget_cell_height" + android:scrollbars="none" > + <LinearLayout + android:id="@+id/widgets_cell_list" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" /> + </HorizontalScrollView> + </RelativeLayout> +</LinearLayout> diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml new file mode 100644 index 000000000..8e7ed161a --- /dev/null +++ b/res/layout/widgets_view.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!-- The top and bottom paddings are defined in this container, but since we want + the list view to span the full width (for touch interception purposes), we + will bake the left/right padding into that view's background itself. --> +<com.android.launcher3.widget.WidgetsContainerView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/widgets_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingTop="@dimen/widget_container_inset" + android:paddingBottom="@dimen/widget_container_inset" + android:descendantFocusability="afterDescendants"> + + <!-- Temporary until finalizing on animation. --> + <include + android:id="@+id/widgets_reveal_view" + layout="@layout/apps_reveal_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" /> + + <LinearLayout + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipChildren="false" + android:orientation="vertical"> + + <android.support.v7.widget.RecyclerView + android:id="@+id/widgets_list_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/quantum_panel_dark"/> + </LinearLayout> +</com.android.launcher3.widget.WidgetsContainerView>
\ No newline at end of file diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml index 1b3418154..06a99842e 100644 --- a/res/values-land/dimens.xml +++ b/res/values-land/dimens.xml @@ -18,9 +18,4 @@ <!-- QSB --> <dimen name="toolbar_button_vertical_padding">8dip</dimen> <dimen name="toolbar_button_horizontal_padding">0dip</dimen> - -<!-- AppsCustomize --> - <dimen name="apps_customize_tab_bar_height">42dp</dimen> - <integer name="apps_customize_widget_cell_count_x">3</integer> - <integer name="apps_customize_widget_cell_count_y">2</integer> </resources> diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml index d80f18c9e..13a1f4098 100644 --- a/res/values-sw600dp/dimens.xml +++ b/res/values-sw600dp/dimens.xml @@ -24,11 +24,9 @@ <dimen name="apps_view_row_height">76dp</dimen> <!-- AppsCustomize --> - <dimen name="apps_customize_tab_bar_height">60dp</dimen> - <dimen name="apps_customize_tab_bar_margin_top">8dp</dimen> - <dimen name="app_widget_preview_label_margin_top">8dp</dimen> - <dimen name="app_widget_preview_label_margin_left">@dimen/app_widget_preview_padding_left</dimen> - <dimen name="app_widget_preview_label_margin_right">@dimen/app_widget_preview_padding_right</dimen> + <dimen name="widget_preview_label_margin_top">8dp</dimen> + <dimen name="widget_preview_label_margin_left">@dimen/widget_preview_padding_left</dimen> + <dimen name="widget_preview_label_margin_right">@dimen/widget_preview_padding_right</dimen> <!-- Cling --> <dimen name="cling_migration_logo_height">400dp</dimen> diff --git a/res/values-v17/styles.xml b/res/values-v17/styles.xml index 11d2a1f82..229375f85 100644 --- a/res/values-v17/styles.xml +++ b/res/values-v17/styles.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <style name="PagedViewWidgetImageView"> - <item name="android:paddingStart">@dimen/app_widget_preview_padding_left</item> + <style name="WidgetImageView"> + <item name="android:paddingStart">@dimen/widget_preview_padding_left</item> </style> </resources> diff --git a/res/values/colors.xml b/res/values/colors.xml index 590a8872b..3a06bd95a 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -36,8 +36,10 @@ <color name="outline_color">#FFFFFFFF</color> <color name="widget_text_panel">#FF374248</color> -<!-- Apps view --> + <!-- Apps view --> <color name="apps_view_scrollbar_thumb_color">#009688</color> <color name="apps_view_section_text_color">#009688</color> + <!-- Widgetss view --> + <color name="widgets_view_section_text_color">#009688</color> </resources> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 735373d69..7c99278a8 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -60,18 +60,9 @@ <dimen name="apps_view_fast_scroll_text_size">40dp</dimen> <!-- AllApps/Customize/AppsCustomize --> - <!-- The height of the tab bar - if this changes, we should update the - external icon width/height above to compensate --> - <dimen name="apps_customize_tab_bar_height">52dp</dimen> - <dimen name="apps_customize_tab_bar_margin_top">0dp</dimen> <dimen name="app_icon_size">48dp</dimen> <dimen name="apps_customize_horizontal_padding">0dp</dimen> - <!-- The AppsCustomize page indicator --> - <dimen name="apps_customize_page_indicator_height">12dp</dimen> - <dimen name="apps_customize_page_indicator_margin">4dp</dimen> - <dimen name="apps_customize_page_indicator_offset">16dp</dimen> - <!-- Drag padding to add to the bottom of drop targets --> <dimen name="drop_target_drag_padding">14dp</dimen> <dimen name="drop_target_text_size">14sp</dimen> @@ -85,12 +76,19 @@ should be. If 0, it will not be scaled at all. --> <dimen name="dragViewScale">12dp</dimen> - <!-- Padding applied to AppWidget previews --> - <dimen name="app_widget_preview_padding_left">16dp</dimen> - <dimen name="app_widget_preview_padding_right">16dp</dimen> - <dimen name="app_widget_preview_padding_top">32dp</dimen> - <dimen name="app_widget_preview_label_vertical_padding">8dp</dimen> - <dimen name="app_widget_preview_label_horizontal_padding">8dp</dimen> +<!-- Widget tray --> + <dimen name="widget_container_inset">8dp</dimen> + <dimen name="widget_preview_size">140dp</dimen> + <dimen name="widget_preview_padding_left">16dp</dimen> + <dimen name="widget_preview_padding_right">16dp</dimen> + <dimen name="widget_preview_padding_top">8dp</dimen> + <dimen name="widget_preview_label_vertical_padding">8dp</dimen> + <dimen name="widget_preview_label_horizontal_padding">8dp</dimen> + + <dimen name="widget_section_height">52dp</dimen> + <dimen name="widget_section_icon_padding">8dp</dimen> + + <dimen name="widget_cell_height">160dp</dimen> <!-- Padding applied to shortcut previews --> <dimen name="shortcut_preview_padding_left">0dp</dimen> diff --git a/res/values/styles.xml b/res/values/styles.xml index 77798f174..94efebc06 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -91,8 +91,8 @@ </style> <!-- Overridden in device overlays --> - <style name="PagedViewWidgetImageView"> - <item name="android:paddingLeft">@dimen/app_widget_preview_padding_left</item> + <style name="WidgetImageView"> + <item name="android:paddingLeft">@dimen/widget_preview_padding_left</item> </style> </resources> diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java index a1391b232..7c6b0664c 100644 --- a/src/com/android/launcher3/AppInfo.java +++ b/src/com/android/launcher3/AppInfo.java @@ -43,7 +43,7 @@ public class AppInfo extends ItemInfo { /** * A bitmap version of the application icon. */ - Bitmap iconBitmap; + public Bitmap iconBitmap; /** * Indicates whether we're using a low res icon @@ -55,7 +55,7 @@ public class AppInfo extends ItemInfo { */ long firstInstallTime; - ComponentName componentName; + public ComponentName componentName; static final int DOWNLOADED_FLAG = 1; static final int UPDATED_SYSTEM_APP_FLAG = 2; @@ -121,12 +121,15 @@ public class AppInfo extends ItemInfo { + " user=" + user + ")"; } + /** + * Helper method used for debugging. + */ public static void dumpApplicationInfoList(String tag, String label, ArrayList<AppInfo> list) { Log.d(tag, label + " size=" + list.size()); for (AppInfo info: list) { - Log.d(tag, " title=\"" + info.title + "\" iconBitmap=" - + info.iconBitmap + " firstInstallTime=" - + info.firstInstallTime); + Log.d(tag, " title=\"" + info.title + "\" iconBitmap=" + info.iconBitmap + + " firstInstallTime=" + info.firstInstallTime + + " componentName=" + info.componentName.getPackageName()); } } diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java deleted file mode 100644 index 58bcf1dbe..000000000 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ /dev/null @@ -1,1060 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3; - -import android.appwidget.AppWidgetHostView; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProviderInfo; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; -import android.util.AttributeSet; -import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.GridLayout; -import android.widget.ImageView; -import android.widget.Toast; - -import com.android.launcher3.DropTarget.DragObject; -import com.android.launcher3.FocusHelper.PagedViewKeyListener; -import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.util.Thunk; - -import java.util.ArrayList; - -/** - * The Apps/Customize page that displays all the applications, widgets, and shortcuts. - */ -public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements - View.OnClickListener, DragSource, - PagedViewWidget.ShortPressListener, LauncherTransitionable { - static final String TAG = "AppsCustomizePagedView"; - - private static Rect sTmpRect = new Rect(); - private static final int[] sTempPosArray = new int[2]; - - /** - * The different content types that this paged view can show. - */ - public enum ContentType { - Widgets - } - private ContentType mContentType = ContentType.Widgets; - - // Refs - @Thunk Launcher mLauncher; - private DragController mDragController; - private final LayoutInflater mLayoutInflater; - private final PackageManager mPackageManager; - - // Save and Restore - private int mSaveInstanceStateItemIndex = -1; - - // Content - private ArrayList<Object> mWidgets; - - // Caching - private IconCache mIconCache; - - // Dimens - private int mContentWidth, mContentHeight; - @Thunk int mWidgetCountX, mWidgetCountY; - private int mNumWidgetPages; - - private final PagedViewKeyListener mKeyListener = new PagedViewKeyListener(); - - private Runnable mInflateWidgetRunnable = null; - private Runnable mBindWidgetRunnable = null; - static final int WIDGET_NO_CLEANUP_REQUIRED = -1; - static final int WIDGET_PRELOAD_PENDING = 0; - static final int WIDGET_BOUND = 1; - static final int WIDGET_INFLATED = 2; - int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED; - int mWidgetLoadingId = -1; - PendingAddWidgetInfo mCreateWidgetInfo = null; - private boolean mDraggingWidget = false; - boolean mPageBackgroundsVisible = true; - - private Toast mWidgetInstructionToast; - - // Deferral of loading widget previews during launcher transitions - private boolean mInTransition; - - WidgetPreviewLoader mWidgetPreviewLoader; - - private boolean mInBulkBind; - private boolean mNeedToUpdatePageCountsAndInvalidateData; - - public AppsCustomizePagedView(Context context, AttributeSet attrs) { - super(context, attrs); - mLayoutInflater = LayoutInflater.from(context); - mPackageManager = context.getPackageManager(); - mWidgets = new ArrayList<>(); - mIconCache = (LauncherAppState.getInstance()).getIconCache(); - - // Save the default widget preview background - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0); - mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2); - mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2); - a.recycle(); - - // The padding on the non-matched dimension for the default widget preview icons - // (top + bottom) - mFadeInAdjacentScreens = false; - - // Unless otherwise specified this view is important for accessibility. - if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); - } - setSinglePageInViewport(); - } - - @Override - protected void init() { - super.init(); - mCenterPagesVertically = false; - - Context context = getContext(); - Resources r = context.getResources(); - setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f); - } - - public void onFinishInflate() { - super.onFinishInflate(); - - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - setPadding(grid.edgeMarginPx, 2 * grid.edgeMarginPx, - grid.edgeMarginPx, 2 * grid.edgeMarginPx); - } - - void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) { - setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight); - } - - WidgetPreviewLoader getWidgetPreviewLoader() { - if (mWidgetPreviewLoader == null) { - mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache(); - } - return mWidgetPreviewLoader; - } - - /** Returns the item index of the center item on this page so that we can restore to this - * item index when we rotate. */ - private int getMiddleComponentIndexOnCurrentPage() { - int i = -1; - if (getPageCount() > 0) { - int currentPage = getCurrentPage(); - if (mContentType == ContentType.Widgets) { - PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage); - int numItemsPerPage = mWidgetCountX * mWidgetCountY; - int childCount = layout.getChildCount(); - if (childCount > 0) { - i = (currentPage * numItemsPerPage) + (childCount / 2); - } - } else { - throw new RuntimeException("Invalid ContentType"); - } - } - return i; - } - - /** Get the index of the item to restore to if we need to restore the current page. */ - int getSaveInstanceStateIndex() { - if (mSaveInstanceStateItemIndex == -1) { - mSaveInstanceStateItemIndex = getMiddleComponentIndexOnCurrentPage(); - } - return mSaveInstanceStateItemIndex; - } - - /** Returns the page in the current orientation which is expected to contain the specified - * item index. */ - int getPageForComponent(int index) { - if (index < 0) return 0; - - int numItemsPerPage = mWidgetCountX * mWidgetCountY; - return index / numItemsPerPage; - } - - /** Restores the page for an item at the specified index */ - void restorePageForIndex(int index) { - if (index < 0) return; - mSaveInstanceStateItemIndex = index; - } - - private void updatePageCounts() { - mNumWidgetPages = (int) Math.ceil(mWidgets.size() / - (float) (mWidgetCountX * mWidgetCountY)); - } - - protected void onDataReady(int width, int height) { - updatePageCounts(); - - // Force a measure to update recalculate the gaps - mContentWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); - mContentHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); - - final boolean hostIsTransitioning = getTabHost().isInTransition(); - int page = getPageForComponent(mSaveInstanceStateItemIndex); - invalidatePageData(Math.max(0, page), hostIsTransitioning); - } - - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - - if (!isDataReady()) { - if (!mWidgets.isEmpty()) { - post(new Runnable() { - // This code triggers requestLayout so must be posted outside of the - // layout pass. - public void run() { - if (Utilities.isViewAttachedToWindow(AppsCustomizePagedView.this)) { - setDataIsReady(); - onDataReady(getMeasuredWidth(), getMeasuredHeight()); - } - } - }); - } - } - } - - public void onPackagesUpdated(ArrayList<Object> widgetsAndShortcuts) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - - // Get the list of widgets and shortcuts - mWidgets.clear(); - for (Object o : widgetsAndShortcuts) { - if (o instanceof LauncherAppWidgetProviderInfo) { - LauncherAppWidgetProviderInfo widget = (LauncherAppWidgetProviderInfo) o; - if (!app.shouldShowAppOrWidgetProvider(widget.provider) && !widget.isCustomWidget) { - continue; - } - - if (widget.minSpanX > 0 && widget.minSpanY > 0) { - // Ensure that all widgets we show can be added on a workspace of this size - int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget); - int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, widget); - int minSpanX = Math.min(spanXY[0], minSpanXY[0]); - int minSpanY = Math.min(spanXY[1], minSpanXY[1]); - if (minSpanX <= (int) grid.numColumns && - minSpanY <= (int) grid.numRows) { - mWidgets.add(widget); - } else { - Log.e(TAG, "Widget " + widget.provider + " can not fit on this device (" + - widget.minWidth + ", " + widget.minHeight + ")"); - } - } else { - Log.e(TAG, "Widget " + widget.provider + " has invalid dimensions (" + - widget.minWidth + ", " + widget.minHeight + ")"); - } - } else { - // just add shortcuts - mWidgets.add(o); - } - } - - updatePageCountsAndInvalidateData(); - } - - public void setBulkBind(boolean bulkBind) { - if (bulkBind) { - mInBulkBind = true; - } else { - mInBulkBind = false; - if (mNeedToUpdatePageCountsAndInvalidateData) { - updatePageCountsAndInvalidateData(); - } - } - } - - private void updatePageCountsAndInvalidateData() { - if (mInBulkBind) { - mNeedToUpdatePageCountsAndInvalidateData = true; - } else { - updatePageCounts(); - invalidateOnDataChange(); - mNeedToUpdatePageCountsAndInvalidateData = false; - } - } - - @Override - public void onClick(View v) { - // When we have exited all apps or are in transition, disregard clicks - if (!mLauncher.isWidgetsViewVisible() - || mLauncher.getWorkspace().isSwitchingState() - || !(v instanceof PagedViewWidget)) return; - - // Let the user know that they have to long press to add a widget - if (mWidgetInstructionToast != null) { - mWidgetInstructionToast.cancel(); - } - mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add, - Toast.LENGTH_SHORT); - mWidgetInstructionToast.show(); - } - - /* - * PagedViewWithDraggableItems implementation - */ - @Override - protected void determineDraggingStart(android.view.MotionEvent ev) { - } - - static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) { - Bundle options = null; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, sTmpRect); - Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher, - info.componentName, null); - - float density = launcher.getResources().getDisplayMetrics().density; - int xPaddingDips = (int) ((padding.left + padding.right) / density); - int yPaddingDips = (int) ((padding.top + padding.bottom) / density); - - options = new Bundle(); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, - sTmpRect.left - xPaddingDips); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, - sTmpRect.top - yPaddingDips); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, - sTmpRect.right - xPaddingDips); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, - sTmpRect.bottom - yPaddingDips); - } - return options; - } - - private void preloadWidget(final PendingAddWidgetInfo info) { - final LauncherAppWidgetProviderInfo pInfo = info.info; - final Bundle options = pInfo.isCustomWidget ? null : - getDefaultOptionsForWidget(mLauncher, info); - - if (pInfo.configure != null) { - info.bindOptions = options; - return; - } - - mWidgetCleanupState = WIDGET_PRELOAD_PENDING; - mBindWidgetRunnable = new Runnable() { - @Override - public void run() { - if (pInfo.isCustomWidget) { - mWidgetCleanupState = WIDGET_BOUND; - return; - } - - mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); - if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed( - mWidgetLoadingId, pInfo, options)) { - mWidgetCleanupState = WIDGET_BOUND; - } - - } - }; - post(mBindWidgetRunnable); - - mInflateWidgetRunnable = new Runnable() { - @Override - public void run() { - if (mWidgetCleanupState != WIDGET_BOUND) { - return; - } - AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView( - getContext(), mWidgetLoadingId, pInfo); - info.boundWidget = hostView; - mWidgetCleanupState = WIDGET_INFLATED; - hostView.setVisibility(INVISIBLE); - int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false); - - // We want the first widget layout to be the correct size. This will be important - // for width size reporting to the AppWidgetManager. - DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0], - unScaledSize[1]); - lp.x = lp.y = 0; - lp.customPosition = true; - hostView.setLayoutParams(lp); - mLauncher.getDragLayer().addView(hostView); - } - }; - post(mInflateWidgetRunnable); - } - - @Override - public void onShortPress(View v) { - // We are anticipating a long press, and we use this time to load bind and instantiate - // the widget. This will need to be cleaned up if it turns out no long press occurs. - if (mCreateWidgetInfo != null) { - // Just in case the cleanup process wasn't properly executed. This shouldn't happen. - cleanupWidgetPreloading(false); - } - mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag()); - preloadWidget(mCreateWidgetInfo); - } - - private void cleanupWidgetPreloading(boolean widgetWasAdded) { - if (!widgetWasAdded) { - // If the widget was not added, we may need to do further cleanup. - PendingAddWidgetInfo info = mCreateWidgetInfo; - mCreateWidgetInfo = null; - - if (mWidgetCleanupState == WIDGET_PRELOAD_PENDING) { - // We never did any preloading, so just remove pending callbacks to do so - removeCallbacks(mBindWidgetRunnable); - removeCallbacks(mInflateWidgetRunnable); - } else if (mWidgetCleanupState == WIDGET_BOUND) { - // Delete the widget id which was allocated - if (mWidgetLoadingId != -1 && !info.isCustomWidget()) { - mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); - } - - // We never got around to inflating the widget, so remove the callback to do so. - removeCallbacks(mInflateWidgetRunnable); - } else if (mWidgetCleanupState == WIDGET_INFLATED) { - // Delete the widget id which was allocated - if (mWidgetLoadingId != -1 && !info.isCustomWidget()) { - mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); - } - - // The widget was inflated and added to the DragLayer -- remove it. - AppWidgetHostView widget = info.boundWidget; - mLauncher.getDragLayer().removeView(widget); - } - } - mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED; - mWidgetLoadingId = -1; - mCreateWidgetInfo = null; - PagedViewWidget.resetShortPressTarget(); - } - - @Override - public void cleanUpShortPress(View v) { - if (!mDraggingWidget) { - cleanupWidgetPreloading(false); - } - } - - private boolean beginDraggingWidget(PagedViewWidget v) { - mDraggingWidget = true; - // Get the widget preview as the drag representation - ImageView image = (ImageView) v.findViewById(R.id.widget_preview); - PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag(); - - // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and - // we abort the drag. - if (image.getDrawable() == null) { - mDraggingWidget = false; - return false; - } - - // Compose the drag image - Bitmap preview; - Bitmap outline; - float scale = 1f; - Point previewPadding = null; - - if (createItemInfo instanceof PendingAddWidgetInfo) { - // This can happen in some weird cases involving multi-touch. We can't start dragging - // the widget if this is null, so we break out. - if (mCreateWidgetInfo == null) { - return false; - } - - PendingAddWidgetInfo createWidgetInfo = mCreateWidgetInfo; - createItemInfo = createWidgetInfo; - int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true); - - FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable(); - float minScale = 1.25f; - int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]); - - int[] previewSizeBeforeScale = new int[1]; - preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info, - maxWidth, null, previewSizeBeforeScale); - // Compare the size of the drag preview to the preview in the AppsCustomize tray - int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0], - v.getActualItemWidth()); - scale = previewWidthInAppsCustomize / (float) preview.getWidth(); - - // The bitmap in the AppsCustomize tray is always the the same size, so there - // might be extra pixels around the preview itself - this accounts for that - if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) { - int padding = - (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2; - previewPadding = new Point(padding, 0); - } - } else { - PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag(); - Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo); - preview = Utilities.createIconBitmap(icon, mLauncher); - createItemInfo.spanX = createItemInfo.spanY = 1; - } - - // Don't clip alpha values for the drag outline if we're using the default widget preview - boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo && - (((PendingAddWidgetInfo) createItemInfo).previewImage == 0)); - - // Save the preview for the outline generation, then dim the preview - outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(), - false); - - // Start the drag - mLauncher.lockScreenOrientation(); - mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha); - mDragController.startDrag(image, preview, this, createItemInfo, - DragController.DRAG_ACTION_COPY, previewPadding, scale); - outline.recycle(); - preview.recycle(); - return true; - } - - @Override - protected boolean beginDragging(final View v) { - if (!super.beginDragging(v)) return false; - - if (v instanceof PagedViewWidget) { - if (!beginDraggingWidget((PagedViewWidget) v)) { - return false; - } - } else { - Log.e(TAG, "Unexpected dragging view: " + v); - } - - // We delay entering spring-loaded mode slightly to make sure the UI - // thready is free of any work. - postDelayed(new Runnable() { - @Override - public void run() { - // We don't enter spring-loaded mode if the drag has been cancelled - if (mLauncher.getDragController().isDragging()) { - // Go into spring loaded mode (must happen before we startDrag()) - mLauncher.enterSpringLoadedDragMode(); - } - } - }, 150); - - return true; - } - - /** - * Clean up after dragging. - * - * @param target where the item was dragged to (can be null if the item was flung) - */ - private void endDragging(View target, boolean isFlingToDelete, boolean success) { - if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() && - !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) { - // Exit spring loaded mode if we have not successfully dropped or have not handled the - // drop in Workspace - mLauncher.exitSpringLoadedDragModeDelayed(true, - Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null); - mLauncher.unlockScreenOrientation(false); - } else { - mLauncher.unlockScreenOrientation(false); - } - } - - @Override - public View getContent() { - if (getChildCount() > 0) { - return getChildAt(0); - } - return null; - } - - @Override - public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) { - mInTransition = true; - if (toWorkspace) { - cancelAllTasks(false); - } - } - - @Override - public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) { - } - - @Override - public void onLauncherTransitionStep(Launcher l, float t) { - } - - @Override - public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { - mInTransition = false; - mForceDrawAllChildrenNextFrame = !toWorkspace; - if (!toWorkspace) { - loadPreviewsForPage(getNextPage()); - } - } - - @Override - public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, - boolean success) { - // Return early and wait for onFlingToDeleteCompleted if this was the result of a fling - if (isFlingToDelete) return; - - endDragging(target, false, success); - - // Display an error message if the drag failed due to there not being enough space on the - // target layout we were dropping on. - if (!success) { - boolean showOutOfSpaceMessage = false; - if (target instanceof Workspace) { - int currentScreen = mLauncher.getCurrentWorkspaceScreen(); - Workspace workspace = (Workspace) target; - CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen); - ItemInfo itemInfo = (ItemInfo) d.dragInfo; - if (layout != null) { - layout.calculateSpans(itemInfo); - showOutOfSpaceMessage = - !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY); - } - } - if (showOutOfSpaceMessage) { - mLauncher.showOutOfSpaceMessage(false); - } - - d.deferDragViewCleanupPostAnimation = false; - } - cleanupWidgetPreloading(success); - mDraggingWidget = false; - } - - @Override - public void onFlingToDeleteCompleted() { - // We just dismiss the drag when we fling, so cleanup here - endDragging(null, true, true); - cleanupWidgetPreloading(false); - mDraggingWidget = false; - } - - @Override - public boolean supportsFlingToDelete() { - return true; - } - - @Override - public boolean supportsAppInfoDropTarget() { - return true; - } - - @Override - public boolean supportsDeleteDropTarget() { - return false; - } - - @Override - public float getIntrinsicIconScaleFactor() { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - return (float) grid.allAppsIconSizePx / grid.iconSizePx; - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - cancelAllTasks(true); - } - - @Override - public void trimMemory() { - super.trimMemory(); - cancelAllTasks(true); - } - - private void cancelAllTasks(boolean clearCompletedTasks) { - for (int page = getPageCount() - 1; page >= 0; page--) { - final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page); - if (layout != null) { - for (int i = 0; i < layout.getChildCount(); i++) { - ((PagedViewWidget) layout.getChildAt(i)).deletePreview(clearCompletedTasks); - } - } - } - } - - - public void setContentType(ContentType type) { - // Widgets appear to be cleared every time you leave, always force invalidate for them - if (mContentType != type || type == ContentType.Widgets) { - int page = (mContentType != type) ? 0 : getCurrentPage(); - mContentType = type; - invalidatePageData(page, true); - } - } - - public ContentType getContentType() { - return mContentType; - } - - public void setPageBackgroundsVisible(boolean visible) { - mPageBackgroundsVisible = visible; - int childCount = getChildCount(); - for (int i = 0; i < childCount; ++i) { - Drawable bg = getChildAt(i).getBackground(); - if (bg != null) { - bg.setAlpha(visible ? 255 : 0); - } - } - } - - /* - * Widgets PagedView implementation - */ - private void setupPage(PagedViewGridLayout layout) { - // Note: We force a measure here to get around the fact that when we do layout calculations - // immediately after syncing, we don't have a proper width. - int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST); - int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST); - - Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel_dark); - if (bg != null) { - bg.setAlpha(mPageBackgroundsVisible ? 255 : 0); - layout.setBackground(bg); - } - layout.measure(widthSpec, heightSpec); - } - - public void syncWidgetPageItems(final int page, final boolean immediate) { - int numItemsPerPage = mWidgetCountX * mWidgetCountY; - - final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page); - - // Calculate the dimensions of each cell we are giving to each widget - final ArrayList<Object> items = new ArrayList<Object>(); - int contentWidth = mContentWidth - layout.getPaddingLeft() - layout.getPaddingRight(); - final int cellWidth = contentWidth / mWidgetCountX; - int contentHeight = mContentHeight - layout.getPaddingTop() - layout.getPaddingBottom(); - - final int cellHeight = contentHeight / mWidgetCountY; - - // Prepare the set of widgets to load previews for in the background - int offset = page * numItemsPerPage; - for (int i = offset; i < Math.min(offset + numItemsPerPage, mWidgets.size()); ++i) { - items.add(mWidgets.get(i)); - } - - // Prepopulate the pages with the other widget info, and fill in the previews later - layout.setColumnCount(layout.getCellCountX()); - for (int i = 0; i < items.size(); ++i) { - Object rawInfo = items.get(i); - PendingAddItemInfo createItemInfo = null; - PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate( - R.layout.apps_customize_widget, layout, false); - - if (rawInfo instanceof LauncherAppWidgetProviderInfo) { - // Fill in the widget information - LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) rawInfo; - createItemInfo = new PendingAddWidgetInfo(info, null); - - widget.applyFromAppWidgetProviderInfo(info, -1, getWidgetPreviewLoader()); - widget.setTag(createItemInfo); - widget.setShortPressListener(this); - } else if (rawInfo instanceof ResolveInfo) { - // Fill in the shortcuts information - ResolveInfo info = (ResolveInfo) rawInfo; - createItemInfo = new PendingAddShortcutInfo(info.activityInfo); - createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; - createItemInfo.componentName = new ComponentName(info.activityInfo.packageName, - info.activityInfo.name); - widget.applyFromResolveInfo(mPackageManager, info, getWidgetPreviewLoader()); - widget.setTag(createItemInfo); - } - - widget.setOnClickListener(this); - widget.setOnLongClickListener(this); - widget.setOnTouchListener(this); - widget.setOnKeyListener(mKeyListener); - - // Layout each widget - int ix = i % mWidgetCountX; - int iy = i / mWidgetCountX; - - if (ix > 0) { - View border = widget.findViewById(R.id.left_border); - border.setVisibility(View.VISIBLE); - } - if (ix < mWidgetCountX - 1) { - View border = widget.findViewById(R.id.right_border); - border.setVisibility(View.VISIBLE); - } - - GridLayout.LayoutParams lp = new GridLayout.LayoutParams( - GridLayout.spec(iy, GridLayout.START), - GridLayout.spec(ix, GridLayout.TOP)); - lp.width = cellWidth; - lp.height = cellHeight; - lp.setGravity(Gravity.TOP | Gravity.START); - layout.addView(widget, lp); - } - - if (immediate && !mInTransition) { - loadPreviewsForPage(page); - } - } - - private void loadPreviewsForPage(int page) { - final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page); - - if (layout != null) { - for (int i = 0; i < layout.getChildCount(); i++) { - ((PagedViewWidget) layout.getChildAt(i)).ensurePreview(); - } - } - } - - @Override - public void syncPages() { - disablePagedViewAnimations(); - - removeAllViews(); - cancelAllTasks(true); - - Context context = getContext(); - if (mContentType == ContentType.Widgets) { - for (int j = 0; j < mNumWidgetPages; ++j) { - PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX, - mWidgetCountY); - setupPage(layout); - addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); - } - } else { - throw new RuntimeException("Invalid ContentType"); - } - - enablePagedViewAnimations(); - } - - @Override - public void syncPageItems(int page, boolean immediate) { - if (mContentType == ContentType.Widgets) { - syncWidgetPageItems(page, immediate); - } else { - Log.e(TAG, "Unexpected ContentType"); - } - } - - // We want our pages to be z-ordered such that the further a page is to the left, the higher - // it is in the z-order. This is important to insure touch events are handled correctly. - View getPageAt(int index) { - return getChildAt(indexToPage(index)); - } - - @Override - protected int indexToPage(int index) { - return getChildCount() - index - 1; - } - - // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack. - @Override - protected void screenScrolled(int screenCenter) { - super.screenScrolled(screenCenter); - enableHwLayersOnVisiblePages(); - } - - private void enableHwLayersOnVisiblePages() { - final int screenCount = getChildCount(); - - getVisiblePages(mTempVisiblePagesRange); - int leftScreen = mTempVisiblePagesRange[0]; - int rightScreen = mTempVisiblePagesRange[1]; - int forceDrawScreen = -1; - if (leftScreen == rightScreen) { - // make sure we're caching at least two pages always - if (rightScreen < screenCount - 1) { - rightScreen++; - forceDrawScreen = rightScreen; - } else if (leftScreen > 0) { - leftScreen--; - forceDrawScreen = leftScreen; - } - } else { - forceDrawScreen = leftScreen + 1; - } - - for (int i = 0; i < screenCount; i++) { - final View layout = (View) getPageAt(i); - if (!(leftScreen <= i && i <= rightScreen && - (i == forceDrawScreen || shouldDrawChild(layout)))) { - layout.setLayerType(LAYER_TYPE_NONE, null); - } - } - - for (int i = 0; i < screenCount; i++) { - final View layout = (View) getPageAt(i); - - if (leftScreen <= i && i <= rightScreen && - (i == forceDrawScreen || shouldDrawChild(layout))) { - if (layout.getLayerType() != LAYER_TYPE_HARDWARE) { - layout.setLayerType(LAYER_TYPE_HARDWARE, null); - } - } - } - } - - protected void overScroll(float amount) { - dampedOverScroll(amount); - } - - /** - * Used by the parent to get the content width to set the tab bar to - * @return - */ - public int getPageContentWidth() { - return mContentWidth; - } - - @Override - protected void onPageEndMoving() { - super.onPageEndMoving(); - mForceDrawAllChildrenNextFrame = true; - // We reset the save index when we change pages so that it will be recalculated on next - // rotation - mSaveInstanceStateItemIndex = -1; - } - - @Override - protected void onPageBeginMoving() { - super.onPageBeginMoving(); - if (!mInTransition) { - getVisiblePages(sTempPosArray); - for (int i = sTempPosArray[0]; i <= sTempPosArray[1]; i++) { - loadPreviewsForPage(i); - } - } - } - - /* - * AllAppsView implementation - */ - public void setup(Launcher launcher, DragController dragController) { - mLauncher = launcher; - mDragController = dragController; - } - - /** - * We should call thise method whenever the core data changes (mWidgets) so that we can - * appropriately determine when to invalidate the PagedView page data. In cases where the data - * has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the - * next onMeasure() pass, which will trigger an invalidatePageData() itself. - */ - private void invalidateOnDataChange() { - if (!isDataReady()) { - // The next layout pass will trigger data-ready if both widgets and apps are set, so - // request a layout to trigger the page data when ready. - requestLayout(); - } else { - cancelAllTasks(false); - invalidatePageData(); - } - } - - public void reset() { - // If we have reset, then we should not continue to restore the previous state - mSaveInstanceStateItemIndex = -1; - - if (mContentType != ContentType.Widgets) { - setContentType(ContentType.Widgets); - } - - if (mCurrentPage != 0) { - invalidatePageData(0); - } - } - - private AppsCustomizeTabHost getTabHost() { - return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane); - } - - public void dumpState() { - // TODO: Dump information related to current list of Applications, Widgets, etc. - dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets); - } - - private void dumpAppWidgetProviderInfoList(String tag, String label, - ArrayList<Object> list) { - Log.d(tag, label + " size=" + list.size()); - for (Object i: list) { - if (i instanceof AppWidgetProviderInfo) { - AppWidgetProviderInfo info = (AppWidgetProviderInfo) i; - Log.d(tag, " label=\"" + info.label + "\" previewImage=" + info.previewImage - + " resizeMode=" + info.resizeMode + " configure=" + info.configure - + " initialLayout=" + info.initialLayout - + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight); - } else if (i instanceof ResolveInfo) { - ResolveInfo info = (ResolveInfo) i; - Log.d(tag, " label=\"" + info.loadLabel(mPackageManager) + "\" icon=" - + info.icon); - } - } - } - - public void surrender() { - // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we - // should stop this now. - - // Stop all background tasks - cancelAllTasks(true); - } - - /* - * We load an extra page on each side to prevent flashes from scrolling and loading of the - * widget previews in the background with the AsyncTasks. - */ - final static int sLookBehindPageCount = 2; - final static int sLookAheadPageCount = 2; - protected int getAssociatedLowerPageBound(int page) { - final int count = getChildCount(); - int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1); - int windowMinIndex = Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0); - return windowMinIndex; - } - protected int getAssociatedUpperPageBound(int page) { - final int count = getChildCount(); - int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1); - int windowMaxIndex = Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1), - count - 1); - return windowMaxIndex; - } - - protected String getCurrentPageDescription() { - int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; - int stringId = R.string.default_scroll_format; - int count = 0; - - if (mContentType == ContentType.Widgets) { - stringId = R.string.apps_customize_widgets_scroll_format; - count = mNumWidgetPages; - } else { - throw new RuntimeException("Invalid ContentType"); - } - - return String.format(getContext().getString(stringId), page + 1, count); - } -} diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java deleted file mode 100644 index 5e2f05c61..000000000 --- a/src/com/android/launcher3/AppsCustomizeTabHost.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3; - -import android.content.Context; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; -import android.view.accessibility.AccessibilityManager; -import android.widget.FrameLayout; - -public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable { - static final String LOG_TAG = "AppsCustomizeTabHost"; - - private static final String WIDGETS_TAB_TAG = "WIDGETS"; - - private AppsCustomizePagedView mPagedView; - private View mContent; - private boolean mInTransition = false; - - private final Rect mInsets = new Rect(); - - public AppsCustomizeTabHost(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Convenience methods to select specific tabs. We want to set the content type immediately - * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view - * reflects the new content (but doesn't do the animation and logic associated with changing - * tabs manually). - */ - void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) { - mPagedView.setContentType(type); - } - - @Override - public void setInsets(Rect insets) { - mInsets.set(insets); - LayoutParams flp = (LayoutParams) mContent.getLayoutParams(); - flp.topMargin = insets.top; - flp.bottomMargin = insets.bottom; - flp.leftMargin = insets.left; - flp.rightMargin = insets.right; - mContent.setLayoutParams(flp); - } - - /** - * Setup the tab host and create all necessary tabs. - */ - @Override - protected void onFinishInflate() { - mPagedView = (AppsCustomizePagedView) findViewById(R.id.apps_customize_pane_content); - mContent = findViewById(R.id.content); - } - - public String getContentTag() { - return getTabTagForContentType(mPagedView.getContentType()); - } - - /** - * Returns the content view used for the launcher transitions. - */ - public View getContentView() { - return findViewById(R.id.apps_customize_pane_content); - } - - /** - * Returns the reveal view used for the launcher transitions. - */ - public View getRevealView() { - return findViewById(R.id.fake_page); - } - - /** - * Returns the page indicators view. - */ - public View getPageIndicators() { - return findViewById(R.id.apps_customize_page_indicator); - } - - /** - * Returns the content type for the specified tab tag. - */ - public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) { - return AppsCustomizePagedView.ContentType.Widgets; - } - - /** - * Returns the tab tag for a given content type. - */ - public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) { - return WIDGETS_TAB_TAG; - } - - /** - * Disable focus on anything under this view in the hierarchy if we are not visible. - */ - @Override - public int getDescendantFocusability() { - if (getVisibility() != View.VISIBLE) { - return ViewGroup.FOCUS_BLOCK_DESCENDANTS; - } - return super.getDescendantFocusability(); - } - - void reset() { - // Reset immediately - mPagedView.reset(); - } - - void trimMemory() { - mPagedView.trimMemory(); - } - - public void onWindowVisible() { - if (getVisibility() == VISIBLE) { - mContent.setVisibility(VISIBLE); - // We unload the widget previews when the UI is hidden, so need to reload pages - // Load the current page synchronously, and the neighboring pages asynchronously - mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true); - mPagedView.loadAssociatedPages(mPagedView.getCurrentPage()); - } - } - @Override - public ViewGroup getContent() { - return mPagedView; - } - - public boolean isInTransition() { - return mInTransition; - } - - /* LauncherTransitionable overrides */ - @Override - public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) { - mPagedView.onLauncherTransitionPrepare(l, animated, toWorkspace); - mInTransition = true; - - if (toWorkspace) { - // Going from All Apps -> Workspace - setVisibilityOfSiblingsWithLowerZOrder(VISIBLE); - } else { - // Going from Workspace -> All Apps - mContent.setVisibility(VISIBLE); - - // Make sure the current page is loaded (we start loading the side pages after the - // transition to prevent slowing down the animation) - // TODO: revisit this - mPagedView.loadAssociatedPages(mPagedView.getCurrentPage()); - } - } - - @Override - public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) { - mPagedView.onLauncherTransitionStart(l, animated, toWorkspace); - } - - @Override - public void onLauncherTransitionStep(Launcher l, float t) { - mPagedView.onLauncherTransitionStep(l, t); - } - - @Override - public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { - mPagedView.onLauncherTransitionEnd(l, animated, toWorkspace); - mInTransition = false; - - if (!toWorkspace) { - // Make sure adjacent pages are loaded (we wait until after the transition to - // prevent slowing down the animation) - mPagedView.loadAssociatedPages(mPagedView.getCurrentPage()); - - // Opening apps, need to announce what page we are on. - AccessibilityManager am = (AccessibilityManager) - getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); - if (am.isEnabled()) { - // Notify the user when the page changes - announceForAccessibility(mPagedView.getCurrentPageDescription()); - } - - // Going from Workspace -> All Apps - // NOTE: We should do this at the end since we check visibility state in some of the - // cling initialization/dismiss code above. - setVisibilityOfSiblingsWithLowerZOrder(INVISIBLE); - } - } - - private void setVisibilityOfSiblingsWithLowerZOrder(int visibility) { - ViewGroup parent = (ViewGroup) getParent(); - if (parent == null) return; - - View appsView = ((Launcher) getContext()).getAppsView(); - View overviewPanel = ((Launcher) getContext()).getOverviewPanel(); - final int count = parent.getChildCount(); - if (!isChildrenDrawingOrderEnabled()) { - for (int i = 0; i < count; i++) { - final View child = parent.getChildAt(i); - if (child == this) { - break; - } else { - if (child.getVisibility() == GONE || child == overviewPanel || - child == appsView) { - continue; - } - child.setVisibility(visibility); - } - } - } else { - throw new RuntimeException("Failed; can't get z-order of views"); - } - } -} diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 63afa3091..f4afb954d 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -45,7 +45,6 @@ import android.util.Log; import android.util.SparseArray; import android.view.MotionEvent; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; @@ -56,6 +55,7 @@ import android.view.animation.LayoutAnimationController; import com.android.launcher3.FolderIcon.FolderRingAnimator; import com.android.launcher3.LauncherAccessibilityDelegate.DragType; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.PendingAddWidgetInfo; import java.util.ArrayList; import java.util.Arrays; @@ -3025,7 +3025,7 @@ public class CellLayout extends ViewGroup { * * @return True if a vacant cell of the specified dimension was found, false otherwise. */ - boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { + public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied); } diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index 1f0dad221..62aa285ab 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -42,6 +42,7 @@ import android.view.animation.LinearInterpolator; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.WidgetsContainerView; public class DeleteDropTarget extends ButtonDropTarget { private static int DELETE_ANIMATION_DURATION = 285; @@ -100,8 +101,9 @@ public class DeleteDropTarget extends ButtonDropTarget { private boolean isAllAppsApplication(DragSource source, Object info) { return source.supportsAppInfoDropTarget() && (info instanceof AppInfo); } - private boolean isAllAppsWidget(DragSource source, Object info) { - if (source instanceof AppsCustomizePagedView) { + + private boolean isWidget(DragSource source, Object info) { + if (source instanceof WidgetsContainerView) { if (info instanceof PendingAddItemInfo) { PendingAddItemInfo addInfo = (PendingAddItemInfo) info; switch (addInfo.itemType) { @@ -173,7 +175,7 @@ public class DeleteDropTarget extends ButtonDropTarget { // If we are dragging an application from AppsCustomize, only show the control if we can // delete the app (it was downloaded), and rename the string to "uninstall" in such a case. // Hide the delete target if it is a widget from AppsCustomize. - if (!willAcceptDrop(info) || isAllAppsWidget(source, info)) { + if (!willAcceptDrop(info) || isWidget(source, info)) { isVisible = false; } if (useUninstallLabel) { @@ -489,13 +491,14 @@ public class DeleteDropTarget extends ButtonDropTarget { } public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) { - final boolean isAllApps = d.dragSource instanceof AppsCustomizePagedView; + final boolean isWidgets = d.dragSource instanceof WidgetsContainerView; + final boolean isAllapps = d.dragSource instanceof AppsContainerView; // Don't highlight the icon as it's animating d.dragView.setColor(0); d.dragView.updateInitialScaleToCurrentScale(); // Don't highlight the target if we are flinging from AllApps - if (isAllApps) { + if (isWidgets || isAllapps) { resetHoverColor(); } @@ -545,7 +548,7 @@ public class DeleteDropTarget extends ButtonDropTarget { public void run() { // If we are dragging from AllApps, then we allow AppsCustomizePagedView to clean up // itself, otherwise, complete the drop to initiate the deletion process - if (!isAllApps) { + if (!isWidgets || !isAllapps) { mLauncher.exitSpringLoadedDragMode(); completeDrop(d); } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 331695acc..ea2852080 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -106,8 +106,8 @@ public class DeviceProfile { public int cellWidthPx; public int cellHeightPx; - int iconSizePx; - int iconTextSizePx; + public int iconSizePx; + public int iconTextSizePx; int iconDrawablePaddingPx; int allAppsIconSizePx; int allAppsIconTextSizePx; @@ -803,64 +803,6 @@ public class DeviceProfile { } } - // Layout AllApps - AppsCustomizeTabHost host = (AppsCustomizeTabHost) - launcher.findViewById(R.id.apps_customize_pane); - if (host != null) { - // Center the all apps page indicator - int pageIndicatorHeight = (int) (pageIndicatorHeightPx * Math.min(1f, - (allAppsIconSizePx / DynamicGrid.DEFAULT_ICON_SIZE_PX))); - pageIndicator = host.findViewById(R.id.apps_customize_page_indicator); - if (pageIndicator != null) { - LinearLayout.LayoutParams lllp = (LinearLayout.LayoutParams) pageIndicator.getLayoutParams(); - lllp.width = LayoutParams.WRAP_CONTENT; - lllp.height = pageIndicatorHeight; - pageIndicator.setLayoutParams(lllp); - } - - AppsCustomizePagedView pagedView = (AppsCustomizePagedView) - host.findViewById(R.id.apps_customize_pane_content); - - FrameLayout fakePageContainer = (FrameLayout) - host.findViewById(R.id.fake_page_container); - FrameLayout fakePage = (FrameLayout) host.findViewById(R.id.fake_page); - - padding = new Rect(); - if (pagedView != null) { - // Constrain the dimensions of all apps so that it does not span the full width - int paddingLR = (availableWidthPx - (allAppsCellWidthPx * allAppsNumCols)) / - (2 * (allAppsNumCols + 1)); - int paddingTB = (availableHeightPx - (allAppsCellHeightPx * allAppsNumRows)) / - (2 * (allAppsNumRows + 1)); - paddingLR = Math.min(paddingLR, (int)((paddingLR + paddingTB) * 0.75f)); - paddingTB = Math.min(paddingTB, (int)((paddingLR + paddingTB) * 0.75f)); - int maxAllAppsWidth = (allAppsNumCols * (allAppsCellWidthPx + 2 * paddingLR)); - int gridPaddingLR = (availableWidthPx - maxAllAppsWidth) / 2; - // Only adjust the side paddings on landscape phones, or tablets - if ((isTablet() || isLandscape) && gridPaddingLR > (allAppsCellWidthPx / 4)) { - padding.left = padding.right = gridPaddingLR; - } - - // The icons are centered, so we can't just offset by the page indicator height - // because the empty space will actually be pageIndicatorHeight + paddingTB - padding.bottom = Math.max(0, pageIndicatorHeight - paddingTB); - - pagedView.setWidgetsPageIndicatorPadding(pageIndicatorHeight); - fakePage.setBackground(res.getDrawable(R.drawable.quantum_panel)); - - // Horizontal padding for the whole paged view - int pagedFixedViewPadding = - res.getDimensionPixelSize(R.dimen.apps_customize_horizontal_padding); - - padding.left += pagedFixedViewPadding; - padding.right += pagedFixedViewPadding; - - pagedView.setPadding(padding.left, padding.top, padding.right, padding.bottom); - fakePageContainer.setPadding(padding.left, padding.top, padding.right, padding.bottom); - - } - } - // Layout the Overview Mode ViewGroup overviewMode = launcher.getOverviewPanel(); if (overviewMode != null) { diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java index 7369eeac2..2a1346ef5 100644 --- a/src/com/android/launcher3/DragSource.java +++ b/src/com/android/launcher3/DragSource.java @@ -22,9 +22,9 @@ import com.android.launcher3.DropTarget.DragObject; /** * Interface defining an object that can originate a drag. - * */ public interface DragSource { + /** * @return whether items dragged from this source supports */ diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java index ff02bbbc3..28e923e67 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -32,7 +32,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.SparseArray; -class FastBitmapDrawable extends Drawable { +public class FastBitmapDrawable extends Drawable { static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() { @@ -72,7 +72,7 @@ class FastBitmapDrawable extends Drawable { private boolean mPressed = false; private ObjectAnimator mPressedAnimator; - FastBitmapDrawable(Bitmap b) { + public FastBitmapDrawable(Bitmap b) { mAlpha = 255; mBitmap = b; setBounds(0, 0, b.getWidth(), b.getHeight()); diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index f4af7f542..f6238dab2 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -44,6 +44,7 @@ import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.PackageItemInfo; import java.util.HashMap; import java.util.HashSet; @@ -454,12 +455,13 @@ public class IconCache { * Fill in {@param appInfo} with the icon and label for {@param packageName} */ public synchronized void getTitleAndIconForApp( - String packageName, UserHandleCompat user, boolean useLowResIcon, AppInfo appInfoOut) { + String packageName, UserHandleCompat user, boolean useLowResIcon, + PackageItemInfo infoOut) { CacheEntry entry = getEntryForPackageLocked(packageName, user, useLowResIcon); - appInfoOut.iconBitmap = entry.icon; - appInfoOut.title = entry.title; - appInfoOut.usingLowResIcon = entry.isLowResIcon; - appInfoOut.contentDescription = entry.contentDescription; + infoOut.iconBitmap = entry.icon; + infoOut.title = entry.title; + infoOut.usingLowResIcon = entry.isLowResIcon; + infoOut.contentDescription = entry.contentDescription; } public synchronized Bitmap getDefaultIcon(UserHandleCompat user) { diff --git a/src/com/android/launcher3/Insettable.java b/src/com/android/launcher3/Insettable.java index 1d2356c65..3b8ef2f93 100644 --- a/src/com/android/launcher3/Insettable.java +++ b/src/com/android/launcher3/Insettable.java @@ -18,6 +18,10 @@ package com.android.launcher3; import android.graphics.Rect; +/** + * Allows the implementing {@link View} to not draw underneath system bars. + * e.g., notification bar on top and home key area on the bottom. + */ public interface Insettable { void setInsets(Rect insets); diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java index f114de221..f7e0ea488 100644 --- a/src/com/android/launcher3/ItemInfo.java +++ b/src/com/android/launcher3/ItemInfo.java @@ -36,7 +36,7 @@ public class ItemInfo { */ static final String EXTRA_PROFILE = "profile"; - static final int NO_ID = -1; + public static final int NO_ID = -1; /** * The id in the settings database for this item @@ -82,7 +82,7 @@ public class ItemInfo { /** * Indicates the Y cell span. */ - int spanY = 1; + public int spanY = 1; /** * Indicates the minimum X cell span. @@ -107,21 +107,21 @@ public class ItemInfo { /** * Title of the item */ - CharSequence title; + public CharSequence title; /** * Content description of the item. */ - CharSequence contentDescription; + public CharSequence contentDescription; /** * The position of the item in a drag-and-drop operation. */ - int[] dropPos = null; + public int[] dropPos = null; - UserHandleCompat user; + public UserHandleCompat user; - ItemInfo() { + public ItemInfo() { user = UserHandleCompat.myUserHandle(); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 2fa2f4ad7..068934e1b 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -103,6 +103,8 @@ import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.PendingAddWidgetInfo; +import com.android.launcher3.widget.WidgetsContainerView; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -130,11 +132,11 @@ public class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener, LauncherStateTransitionAnimation.Callbacks { - static final String TAG = "Launcher"; - static final boolean LOGD = false; + static final String TAG = "Launcher - MERONG"; + static final boolean LOGD = true; static final boolean PROFILE_STARTUP = false; - static final boolean DEBUG_WIDGETS = false; + static final boolean DEBUG_WIDGETS = true; static final boolean DEBUG_STRICT_MODE = false; static final boolean DEBUG_RESUME_TIME = false; static final boolean DEBUG_DUMP_LOG = false; @@ -264,9 +266,13 @@ public class Launcher extends Activity private View mAllAppsButton; private SearchDropTargetBar mSearchDropTargetBar; + + // Main container view for the all apps screen. @Thunk AppsContainerView mAppsView; - @Thunk AppsCustomizeTabHost mAppsCustomizeTabHost; - private AppsCustomizePagedView mAppsCustomizeContent; + + // Main container view for the widget tray screen. + private WidgetsContainerView mWidgetsView; + private boolean mAutoAdvanceRunning = false; private AppWidgetHostView mQsb; @@ -672,7 +678,7 @@ public class Launcher extends Activity return mInflater; } - boolean isDraggingEnabled() { + public boolean isDraggingEnabled() { // We prevent dragging when we are loading the workspace as it is possible to pick up a view // that is subsequently removed from the workspace in startBinding(). return !mModel.isLoadingWorkspace(); @@ -1013,15 +1019,9 @@ public class Launcher extends Activity startTimeCallbacks = System.currentTimeMillis(); } - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.setBulkBind(true); - } for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) { mBindOnResumeCallbacks.get(i).run(); } - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.setBulkBind(false); - } mBindOnResumeCallbacks.clear(); if (DEBUG_RESUME_TIME) { Log.d(TAG, "Time spent processing callbacks in onResume: " + @@ -1213,9 +1213,8 @@ public class Launcher extends Activity if (mModel.isCurrentCallbacks(this)) { mModel.stopLoader(); } - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.surrender(); - } + //TODO(hyunyoungs): stop the widgets loader when there is a rotation. + return Boolean.TRUE; } @@ -1336,19 +1335,6 @@ public class Launcher extends Activity mRestoring = true; } - // Restore the AppsCustomize tab - if (mAppsCustomizeTabHost != null) { - String curTab = savedState.getString("apps_customize_currentTab"); - if (curTab != null) { - mAppsCustomizeTabHost.setContentTypeImmediate( - mAppsCustomizeTabHost.getContentTypeForTabTag(curTab)); - mAppsCustomizeContent.loadAssociatedPages( - mAppsCustomizeContent.getCurrentPage()); - } - - int currentIndex = savedState.getInt("apps_customize_currentIndex"); - mAppsCustomizeContent.restorePageForIndex(currentIndex); - } mItemIdToViewId = (HashMap<Integer, Integer>) savedState.getSerializable(RUNTIME_STATE_VIEW_IDS); } @@ -1434,10 +1420,7 @@ public class Launcher extends Activity mAppsView = (AppsContainerView) findViewById(R.id.apps_view); // Setup AppsCustomize - mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane); - mAppsCustomizeContent = (AppsCustomizePagedView) - mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content); - mAppsCustomizeContent.setup(this, dragController); + mWidgetsView = (WidgetsContainerView) findViewById(R.id.widgets_view); // Setup the drag controller (drop targets have to be added in reverse order in priority) dragController.setDragScoller(mWorkspace); @@ -1651,7 +1634,7 @@ public class Launcher extends Activity // Reset AllApps to its initial state only if we are not in the middle of // processing a multi-step drop - if (mAppsView != null && mAppsCustomizeTabHost != null && + if (mAppsView != null && mWidgetsView != null && mPendingAddInfo.container == ItemInfo.NO_ID) { showWorkspace(false); } @@ -1735,7 +1718,6 @@ public class Launcher extends Activity // you're in All Apps and click home to go to the workspace. onWindowVisibilityChanged // is a more appropriate event to handle if (mVisible) { - mAppsCustomizeTabHost.onWindowVisible(); if (!mWorkspaceLoading) { final ViewTreeObserver observer = mWorkspace.getViewTreeObserver(); // We want to let Launcher draw itself at least once before we force it to build @@ -1839,7 +1821,7 @@ public class Launcher extends Activity launcherInfo.hostView = null; } - void showOutOfSpaceMessage(boolean isHotseatLayout) { + public void showOutOfSpaceMessage(boolean isHotseatLayout) { int strId = (isHotseatLayout ? R.string.hotseat_out_of_space : R.string.out_of_space); Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show(); } @@ -1852,8 +1834,8 @@ public class Launcher extends Activity return mAppsView; } - public AppsCustomizeTabHost getWidgetsView() { - return mAppsCustomizeTabHost; + public WidgetsContainerView getWidgetsView() { + return mWidgetsView; } public Workspace getWorkspace() { @@ -1946,9 +1928,9 @@ public class Launcher extends Activity mAppsView.scrollToTop(); } - // Reset the apps customize page - if (!alreadyOnHome && mAppsCustomizeTabHost != null) { - mAppsCustomizeTabHost.reset(); + // Reset the widgets view + if (!alreadyOnHome && mWidgetsView != null) { + mWidgetsView.scrollToTop(); } if (mLauncherCallbacks != null) { @@ -2003,16 +1985,8 @@ public class Launcher extends Activity outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id); } - // Save the current AppsCustomize tab - if (mAppsCustomizeTabHost != null) { - AppsCustomizePagedView.ContentType type = mAppsCustomizeContent.getContentType(); - String currentTabTag = mAppsCustomizeTabHost.getTabTagForContentType(type); - if (currentTabTag != null) { - outState.putString("apps_customize_currentTab", currentTabTag); - } - int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex(); - outState.putInt("apps_customize_currentIndex", currentIndex); - } + // Save the current widgets tray? + // TODO(hyunyoungs) outState.putSerializable(RUNTIME_STATE_VIEW_IDS, mItemIdToViewId); if (mLauncherCallbacks != null) { @@ -3276,9 +3250,7 @@ public class Launcher extends Activity SQLiteDatabase.releaseMemory(); // This clears all widget bitmaps from the widget tray - if (mAppsCustomizeTabHost != null) { - mAppsCustomizeTabHost.trimMemory(); - } + // TODO(hyunyoungs) } if (mLauncherCallbacks != null) { mLauncherCallbacks.onTrimMemory(level); @@ -3355,15 +3327,16 @@ public class Launcher extends Activity * Shows the widgets view. */ void showWidgetsView(boolean animated, boolean resetPageToZero) { + Log.d(TAG, "showWidgetsView:" + animated + " resetPageToZero:" + resetPageToZero); if (resetPageToZero) { - mAppsCustomizeTabHost.reset(); + mWidgetsView.scrollToTop(); } showAppsOrWidgets(animated, State.WIDGETS); - mAppsCustomizeTabHost.post(new Runnable() { + + mWidgetsView.post(new Runnable() { @Override public void run() { - // We post this in-case the all apps view isn't yet constructed. - mAppsCustomizeTabHost.requestFocus(); + mWidgetsView.requestFocus(); } }); } @@ -3394,7 +3367,9 @@ public class Launcher extends Activity .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } - void enterSpringLoadedDragMode() { + public void enterSpringLoadedDragMode() { + Log.d(TAG, String.format("enterSpringLoadedDragMode [mState=%s", + mState.name())); if (mState == State.WORKSPACE || mState == State.APPS_SPRING_LOADED || mState == State.WIDGETS_SPRING_LOADED) { return; @@ -3405,7 +3380,7 @@ public class Launcher extends Activity mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED; } - void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay, + public void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay, final Runnable onCompleteRunnable) { if (mState != State.APPS_SPRING_LOADED && mState != State.WIDGETS_SPRING_LOADED) return; @@ -3413,10 +3388,12 @@ public class Launcher extends Activity @Override public void run() { if (successfulDrop) { + // TODO(hyunyoungs): verify if this hack is still needed, if not, delete. + // // Before we show workspace, hide all apps again because // exitSpringLoadedDragMode made it visible. This is a bit hacky; we should // clean up our state transition functions - mAppsCustomizeTabHost.setVisibility(View.GONE); + mWidgetsView.setVisibility(View.GONE); showWorkspace(true, onCompleteRunnable); } else { exitSpringLoadedDragMode(); @@ -3918,8 +3895,8 @@ public class Launcher extends Activity pendingInfo.spanY = item.spanY; pendingInfo.minSpanX = item.minSpanX; pendingInfo.minSpanY = item.minSpanY; - Bundle options = - AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo); + Bundle options = null; + // AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo); int newWidgetId = mAppWidgetHost.allocateAppWidgetId(); boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( @@ -4122,9 +4099,9 @@ public class Launcher extends Activity if (mAppsView != null) { mAppsView.setApps(apps); } - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.onPackagesUpdated( - LauncherModel.getSortedWidgetsAndShortcuts(this, false /* refresh */)); + if (mWidgetsView != null) { + mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false), + getPackageManager()); } if (mLauncherCallbacks != null) { mLauncherCallbacks.bindAllApplications(apps); @@ -4276,15 +4253,16 @@ public class Launcher extends Activity mWidgetsAndShortcuts = null; } }; + public void bindPackagesUpdated(final ArrayList<Object> widgetsAndShortcuts) { if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) { mWidgetsAndShortcuts = widgetsAndShortcuts; return; } - // Update the widgets pane - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.onPackagesUpdated(widgetsAndShortcuts); + if (mWidgetsView != null) { + mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false), + getPackageManager()); } } @@ -4577,10 +4555,8 @@ public class Launcher extends Activity Log.d(TAG, "mSavedInstanceState=" + mSavedInstanceState); Log.d(TAG, "sFolders.size=" + sFolders.size()); mModel.dumpState(); + // TODO(hyunyoungs): add mWidgetsView.dumpState(); or mWidgetsModel.dumpState(); - if (mAppsCustomizeContent != null) { - mAppsCustomizeContent.dumpState(); - } Log.d(TAG, "END launcher3 dump state"); } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 2a08b8176..3bd385028 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -141,7 +141,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { return mModel; } - LauncherAccessibilityDelegate getAccessibilityDelegate() { + public LauncherAccessibilityDelegate getAccessibilityDelegate() { return mAccessibilityDelegate; } diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java index aeef0daeb..bb4580ce7 100644 --- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java @@ -16,10 +16,10 @@ import android.os.Parcel; public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { public boolean isCustomWidget = false; - int spanX = -1; - int spanY = -1; - int minSpanX = -1; - int minSpanY = -1; + public int spanX = -1; + public int spanY = -1; + public int minSpanX = -1; + public int minSpanY = -1; public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context, AppWidgetProviderInfo info) { @@ -78,10 +78,11 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { return super.loadIcon(context, cache.getFullResIconDpi()); } - public String toString() { + public String toString(PackageManager pm) { if (isCustomWidget) { - return "LauncherAppWidgetProviderInfo(" + provider + ")"; + return "WidgetProviderInfo(" + provider + ")"; } - return super.toString(); + return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s span(%d, %d) minSpan(%d, %d)", + provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm), spanX, spanY, minSpanX, minSpanY); } } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 1f36331ec..98ba09bc6 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -3628,7 +3628,7 @@ public class LauncherModel extends BroadcastReceiver private final HashMap<Object, String> mLabelCache; private final Collator mCollator; - WidgetAndShortcutNameComparator(Context context) { + public WidgetAndShortcutNameComparator(Context context) { mManager = AppWidgetManagerCompat.getInstance(context); mPackageManager = context.getPackageManager(); mLabelCache = new HashMap<Object, String>(); diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index d657cb50f..111de409e 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -22,7 +22,7 @@ import android.provider.BaseColumns; /** * Settings related utilities. */ -class LauncherSettings { +public class LauncherSettings { /** Columns required on table staht will be subject to backup and restore. */ static interface ChangeLogColumns extends BaseColumns { /** @@ -121,7 +121,7 @@ class LauncherSettings { /** * Favorites. */ - static final class Favorites implements BaseLauncherColumns { + public static final class Favorites implements BaseLauncherColumns { /** * The content:// style URL for this table */ @@ -217,12 +217,12 @@ class LauncherSettings { /** * The favorite is a widget */ - static final int ITEM_TYPE_APPWIDGET = 4; + public static final int ITEM_TYPE_APPWIDGET = 4; /** * The favorite is a custom widget provided by the launcher */ - static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5; + public static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5; /** * The favorite is a clock diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index eacf3415e..e92bfb053 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -23,6 +23,7 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.TimeInterpolator; import android.content.res.Resources; +import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.view.ViewAnimationUtils; @@ -30,6 +31,7 @@ import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.WidgetsContainerView; import java.util.HashMap; @@ -179,20 +181,12 @@ public class LauncherStateTransitionAnimation { * Starts an animation to the widgets view. */ public void startAnimationToWidgets(final boolean animated) { - final AppsCustomizeTabHost toView = mLauncher.getWidgetsView(); + final WidgetsContainerView toView = mLauncher.getWidgetsView(); PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() { @Override public void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) { - // Hide the real page background, and swap in the fake one - ((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(false); - revealView.setBackground( - mLauncher.getResources().getDrawable(R.drawable.quantum_panel_dark)); - } - @Override - public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) { - // Show the real page background - ((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(true); + revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark)); } @Override public float getMaterialRevealViewFinalAlpha(View revealView) { @@ -204,7 +198,7 @@ public class LauncherStateTransitionAnimation { } }; startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, toView, toView.getContentView(), - toView.getRevealView(), toView.getPageIndicators(), animated, cb); + toView.getRevealView(), null, animated, cb); } /** @@ -500,45 +494,9 @@ public class LauncherStateTransitionAnimation { private void startAnimationToWorkspaceFromWidgets(final Launcher.State fromState, final Workspace.State toWorkspaceState, final boolean animated, final Runnable onCompleteRunnable) { - AppsCustomizeTabHost widgetsView = mLauncher.getWidgetsView(); + WidgetsContainerView widgetsView = mLauncher.getWidgetsView(); PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() { @Override - public void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) { - AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView); - - // Hide the real page background, and swap in the fake one - pagedView.stopScrolling(); - pagedView.setPageBackgroundsVisible(false); - revealView.setBackground( - mLauncher.getResources().getDrawable(R.drawable.quantum_panel_dark)); - - // Hide the side pages of the Widget tray to avoid some ugly edge cases - final View currentPage = pagedView.getPageAt(pagedView.getNextPage()); - int count = pagedView.getChildCount(); - for (int i = 0; i < count; i++) { - View child = pagedView.getChildAt(i); - if (child != currentPage) { - child.setVisibility(View.INVISIBLE); - } - } - } - @Override - public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) { - AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView); - - // Show the real page background and force-update the page - pagedView.setPageBackgroundsVisible(true); - pagedView.setCurrentPage(pagedView.getNextPage()); - pagedView.updateCurrentPageScroll(); - - // Unhide the side pages - int count = pagedView.getChildCount(); - for (int i = 0; i < count; i++) { - View child = pagedView.getChildAt(i); - child.setVisibility(View.VISIBLE); - } - } - @Override public float getMaterialRevealViewFinalYDrift(View revealView) { return revealView.getMeasuredHeight() / 2; } @@ -559,7 +517,7 @@ public class LauncherStateTransitionAnimation { }; startAnimationToWorkspaceFromOverlay(toWorkspaceState, widgetsView, widgetsView.getContentView(), widgetsView.getRevealView(), - widgetsView.getPageIndicators(), animated, onCompleteRunnable, cb); + null, animated, onCompleteRunnable, cb); } /** diff --git a/src/com/android/launcher3/PagedViewWithDraggableItems.java b/src/com/android/launcher3/PagedViewWithDraggableItems.java deleted file mode 100644 index f0743cf1c..000000000 --- a/src/com/android/launcher3/PagedViewWithDraggableItems.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - - -/* Class that does most of the work of enabling dragging items out of a PagedView by performing a - * vertical drag. Used by both CustomizePagedView and AllAppsPagedView. - * Subclasses must do the following: - * * call setDragSlopeThreshold after making an instance of the PagedViewWithDraggableItems - * * call child.setOnLongClickListener(this) and child.setOnTouchListener(this) on all children - * (good place to do it is in syncPageItems) - * * override beginDragging(View) (but be careful to call super.beginDragging(View) - * - */ -public abstract class PagedViewWithDraggableItems extends PagedView - implements View.OnLongClickListener, View.OnTouchListener { - private View mLastTouchedItem; - private boolean mIsDragging; - private boolean mIsDragEnabled; - private float mDragSlopeThreshold; - private Launcher mLauncher; - - public PagedViewWithDraggableItems(Context context) { - this(context, null); - } - - public PagedViewWithDraggableItems(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - mLauncher = (Launcher) context; - } - - protected boolean beginDragging(View v) { - boolean wasDragging = mIsDragging; - mIsDragging = true; - return !wasDragging; - } - - protected void cancelDragging() { - mIsDragging = false; - mLastTouchedItem = null; - mIsDragEnabled = false; - } - - private void handleTouchEvent(MotionEvent ev) { - final int action = ev.getAction(); - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - cancelDragging(); - mIsDragEnabled = true; - break; - case MotionEvent.ACTION_MOVE: - if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging && mIsDragEnabled) { - determineDraggingStart(ev); - } - break; - } - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - handleTouchEvent(ev); - return super.onInterceptTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - handleTouchEvent(ev); - return super.onTouchEvent(ev); - } - - public void trimMemory() { - mLastTouchedItem = null; - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - mLastTouchedItem = v; - mIsDragEnabled = true; - return false; - } - - @Override - public boolean onLongClick(View v) { - // Return early if this is not initiated from a touch - if (!v.isInTouchMode()) return false; - // Return early if we are still animating the pages - if (mNextPage != INVALID_PAGE) return false; - // When we have exited all apps or are in transition, disregard long clicks - if (!mLauncher.isWidgetsViewVisible() || - mLauncher.getWorkspace().isSwitchingState()) return false; - // Return if global dragging is not enabled - if (!mLauncher.isDraggingEnabled()) return false; - - return beginDragging(v); - } - - /* - * Determines if we should change the touch state to start scrolling after the - * user moves their touch point too far. - */ - protected void determineScrollingStart(MotionEvent ev) { - if (!mIsDragging) super.determineScrollingStart(ev); - } - - /* - * Determines if we should change the touch state to start dragging after the - * user moves their touch point far enough. - */ - protected void determineDraggingStart(MotionEvent ev) { - /* - * Locally do absolute value. mLastMotionX is set to the y value - * of the down event. - */ - final int pointerIndex = ev.findPointerIndex(mActivePointerId); - final float x = ev.getX(pointerIndex); - final float y = ev.getY(pointerIndex); - final int xDiff = (int) Math.abs(x - mLastMotionX); - final int yDiff = (int) Math.abs(y - mLastMotionY); - - final int touchSlop = mTouchSlop; - boolean yMoved = yDiff > touchSlop; - boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold; - - if (isUpwardMotion && yMoved && mLastTouchedItem != null) { - // Drag if the user moved far enough along the Y axis - beginDragging(mLastTouchedItem); - - // Cancel any pending long press - if (mAllowLongPress) { - mAllowLongPress = false; - // Try canceling the long press. It could also have been scheduled - // by a distant descendant, so use the mAllowLongPress flag to block - // everything - final View currentPage = getPageAt(mCurrentPage); - if (currentPage != null) { - currentPage.cancelLongPress(); - } - } - } - } - - public void setDragSlopeThreshold(float dragSlopeThreshold) { - mDragSlopeThreshold = dragSlopeThreshold; - } - - @Override - protected void onDetachedFromWindow() { - cancelDragging(); - super.onDetachedFromWindow(); - } -} diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java index ac54a262f..1aaf85bbd 100644 --- a/src/com/android/launcher3/PendingAddItemInfo.java +++ b/src/com/android/launcher3/PendingAddItemInfo.java @@ -16,93 +16,17 @@ package com.android.launcher3; -import android.appwidget.AppWidgetHostView; import android.content.ComponentName; -import android.content.pm.ActivityInfo; -import android.os.Bundle; -import android.os.Parcelable; /** - * We pass this object with a drag from the customization tray + * Meta data that is used for deferred binding. + * e.g., this object is used to pass information on dragable targets when they are dropped onto + * the workspace from another container. */ -class PendingAddItemInfo extends ItemInfo { +public class PendingAddItemInfo extends ItemInfo { + /** * The component that will be created. */ - ComponentName componentName; -} - -class PendingAddShortcutInfo extends PendingAddItemInfo { - - ActivityInfo shortcutActivityInfo; - - public PendingAddShortcutInfo(ActivityInfo activityInfo) { - shortcutActivityInfo = activityInfo; - } - - @Override - public String toString() { - return "Shortcut: " + shortcutActivityInfo.packageName; - } -} - -class PendingAddWidgetInfo extends PendingAddItemInfo { - int minWidth; - int minHeight; - int minResizeWidth; - int minResizeHeight; - int previewImage; - int icon; - LauncherAppWidgetProviderInfo info; - AppWidgetHostView boundWidget; - Bundle bindOptions = null; - - public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, Parcelable data) { - if (i.isCustomWidget) { - itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; - } else { - itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; - } - this.info = i; - componentName = i.provider; - minWidth = i.minWidth; - minHeight = i.minHeight; - minResizeWidth = i.minResizeWidth; - minResizeHeight = i.minResizeHeight; - previewImage = i.previewImage; - icon = i.icon; - - spanX = i.spanX; - spanY = i.spanY; - minSpanX = i.minSpanX; - minSpanY = i.minSpanY; - } - - public boolean isCustomWidget() { - return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; - } - - // Copy constructor - public PendingAddWidgetInfo(PendingAddWidgetInfo copy) { - minWidth = copy.minWidth; - minHeight = copy.minHeight; - minResizeWidth = copy.minResizeWidth; - minResizeHeight = copy.minResizeHeight; - previewImage = copy.previewImage; - icon = copy.icon; - info = copy.info; - boundWidget = copy.boundWidget; - componentName = copy.componentName; - itemType = copy.itemType; - spanX = copy.spanX; - spanY = copy.spanY; - minSpanX = copy.minSpanX; - minSpanY = copy.minSpanY; - bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone(); - } - - @Override - public String toString() { - return "Widget: " + componentName.toShortString(); - } + public ComponentName componentName; } diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 1043e2ee0..5c3ed9272 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -32,6 +32,7 @@ import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.WidgetCell; import java.lang.ref.WeakReference; import java.util.Collections; @@ -45,6 +46,7 @@ import java.util.concurrent.ExecutionException; public class WidgetPreviewLoader { private static final String TAG = "WidgetPreviewLoader"; + private static final boolean DEBUG = false; private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f; @@ -78,7 +80,7 @@ public class WidgetPreviewLoader { * @return a request id which can be used to cancel the request. */ public PreviewLoadRequest getPreview(final Object o, int previewWidth, int previewHeight, - PagedViewWidget caller, Bitmap[] immediateResult) { + WidgetCell caller, Bitmap[] immediateResult) { String size = previewWidth + "x" + previewHeight; WidgetCacheKey key = getObjectKey(o, size); @@ -576,21 +578,26 @@ public class WidgetPreviewLoader { private final Object mInfo; private final int mPreviewHeight; private final int mPreviewWidth; - private final PagedViewWidget mCaller; + private final WidgetCell mCaller; PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth, - int previewHeight, PagedViewWidget caller) { + int previewHeight, WidgetCell caller) { mKey = key; mInfo = info; mPreviewHeight = previewHeight; mPreviewWidth = previewWidth; mCaller = caller; + if (DEBUG) { + Log.d(TAG, String.format("%s, %s, %d, %d", + mKey, mInfo, mPreviewHeight, mPreviewWidth)); + } } - @Override protected Bitmap doInBackground(Void... params) { Bitmap unusedBitmap = null; + + // TODO(hyunyoungs): Figure out why this path causes concurrency issue. synchronized (mUnusedBitmaps) { // Check if we can use a bitmap for (Bitmap candidate : mUnusedBitmaps) { @@ -608,7 +615,6 @@ public class WidgetPreviewLoader { mUnusedBitmaps.remove(unusedBitmap); } } - if (isCancelled()) { return null; } diff --git a/src/com/android/launcher3/WidgetsContainerView.java b/src/com/android/launcher3/WidgetsContainerView.java deleted file mode 100644 index 7004d8b29..000000000 --- a/src/com/android/launcher3/WidgetsContainerView.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.android.launcher3; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.FrameLayout; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - - -class SectionedWidgetsRow { - String section; - List<List<Object>> widgets; - - public SectionedWidgetsRow(String sc) { - section = sc; - } -} - -class SectionedWidgetsAlgorithm { - public List<SectionedWidgetsRow> computeSectionedWidgetRows(List<Object> sortedWidgets, - int widgetsPerRow) { - List<SectionedWidgetsRow> rows = new ArrayList<>(); - LinkedHashMap<String, List<Object>> sections = computeSectionedApps(sortedWidgets); - for (Map.Entry<String, List<Object>> sectionEntry : sections.entrySet()) { - String section = sectionEntry.getKey(); - SectionedWidgetsRow row = new SectionedWidgetsRow(section); - List<Object> widgets = sectionEntry.getValue(); - int numRows = (int) Math.ceil((float) widgets.size() / widgetsPerRow); - for (int i = 0; i < numRows; i++) { - List<Object> widgetsInRow = new ArrayList<>(); - int offset = i * widgetsPerRow; - for (int j = 0; j < widgetsPerRow; j++) { - widgetsInRow.add(widgets.get(offset + j)); - } - row.widgets.add(widgetsInRow); - } - } - return rows; - } - - private LinkedHashMap<String, List<Object>> computeSectionedApps(List<Object> sortedWidgets) { - LinkedHashMap<String, List<Object>> sections = new LinkedHashMap<>(); - for (Object info : sortedWidgets) { - String section = getSection(info); - List<Object> sectionedWidgets = sections.get(section); - if (sectionedWidgets == null) { - sectionedWidgets = new ArrayList<>(); - sections.put(section, sectionedWidgets); - } - sectionedWidgets.add(info); - } - return sections; - } - - private String getSection(Object widgetOrShortcut) { - return "UNKNOWN"; - } -} - -/** - * The widgets list view container. - */ -public class WidgetsContainerView extends FrameLayout { - - - public WidgetsContainerView(Context context) { - this(context, null); - } - - public WidgetsContainerView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - protected void onFinishInflate() { - } -} diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index a79add05f..8cc99a044 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -71,6 +71,8 @@ import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.WallpaperUtils; +import com.android.launcher3.widget.PendingAddShortcutInfo; +import com.android.launcher3.widget.PendingAddWidgetInfo; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/com/android/launcher3/widget/PackageItemInfo.java b/src/com/android/launcher3/widget/PackageItemInfo.java new file mode 100644 index 000000000..d7edf2294 --- /dev/null +++ b/src/com/android/launcher3/widget/PackageItemInfo.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.widget; + +import android.content.ComponentName; +import android.graphics.Bitmap; + +import com.android.launcher3.ItemInfo; + +import java.util.Arrays; + +/** + * Represents a {@link Package} in the widget tray section. + */ +public class PackageItemInfo extends ItemInfo { + private static final String TAG = "PackageInfo"; + + /** + * A bitmap version of the application icon. + */ + public Bitmap iconBitmap; + + /** + * Indicates whether we're using a low res icon + */ + public boolean usingLowResIcon; + + public ComponentName componentName; + + int flags = 0; + + PackageItemInfo() { + } + + @Override + public String toString() { + return "PackageItemInfo(title=" + title.toString() + " id=" + this.id + + " type=" + this.itemType + " container=" + this.container + + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + + " user=" + user + ")"; + } +} diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java new file mode 100644 index 000000000..a56985083 --- /dev/null +++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.widget; + +import android.content.ComponentName; +import android.content.pm.ActivityInfo; + +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.PendingAddItemInfo; + +/** + * Meta data used for late binding of the short cuts. + * + * @see {@link PendingAddItemInfo} + */ +public class PendingAddShortcutInfo extends PendingAddItemInfo { + + ActivityInfo activityInfo; + + public PendingAddShortcutInfo(ActivityInfo activityInfo) { + this.activityInfo = activityInfo; + componentName = new ComponentName(activityInfo.packageName, activityInfo.name); + itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; + } + + @Override + public String toString() { + return String.format("PendingAddShortcutInfo package=%s, name=%s", + activityInfo.packageName, activityInfo.name); + } +} diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java new file mode 100644 index 000000000..db1699818 --- /dev/null +++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.widget; + +import android.appwidget.AppWidgetHostView; +import android.os.Bundle; +import android.os.Parcelable; + +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.PendingAddItemInfo; + +/** + * Meta data used for late binding of {@link LauncherAppWidgetProviderInfo}. + * + * @see {@link PendingAddItemInfo} + */ +public class PendingAddWidgetInfo extends PendingAddItemInfo { + public int minWidth; + public int minHeight; + public int minResizeWidth; + public int minResizeHeight; + public int previewImage; + public int icon; + public LauncherAppWidgetProviderInfo info; + public AppWidgetHostView boundWidget; + public Bundle bindOptions = null; + + public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, Parcelable data) { + if (i.isCustomWidget) { + itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; + } else { + itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; + } + this.info = i; + componentName = i.provider; + minWidth = i.minWidth; + minHeight = i.minHeight; + minResizeWidth = i.minResizeWidth; + minResizeHeight = i.minResizeHeight; + previewImage = i.previewImage; + icon = i.icon; + + spanX = i.spanX; + spanY = i.spanY; + minSpanX = i.minSpanX; + minSpanY = i.minSpanY; + } + + public boolean isCustomWidget() { + return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET; + } + + // Copy constructor + public PendingAddWidgetInfo(PendingAddWidgetInfo copy) { + minWidth = copy.minWidth; + minHeight = copy.minHeight; + minResizeWidth = copy.minResizeWidth; + minResizeHeight = copy.minResizeHeight; + previewImage = copy.previewImage; + icon = copy.icon; + info = copy.info; + boundWidget = copy.boundWidget; + componentName = copy.componentName; + itemType = copy.itemType; + spanX = copy.spanX; + spanY = copy.spanY; + minSpanX = copy.minSpanX; + minSpanY = copy.minSpanY; + bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone(); + } + + @Override + public String toString() { + return String.format("PendingAddWidgetInfo package=%s, name=%s", + componentName.getPackageName(), componentName.getShortClassName()); + } +} diff --git a/src/com/android/launcher3/PagedViewWidget.java b/src/com/android/launcher3/widget/WidgetCell.java index d9ca7be87..ccd67ce41 100644 --- a/src/com/android/launcher3/PagedViewWidget.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.launcher3; +package com.android.launcher3.widget; import android.content.Context; import android.content.pm.PackageManager; @@ -23,6 +23,7 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.Log; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; @@ -31,15 +32,31 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.FastBitmapDrawable; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.R; +import com.android.launcher3.WidgetPreviewLoader; import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest; import com.android.launcher3.compat.AppWidgetManagerCompat; /** - * The linear layout used strictly for the widget/wallpaper tab of the customization tray + * The linear layout used strictly for the widget tray. */ -public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListener { +public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { - private static PagedViewWidget sShortpressTarget = null; + private static final String TAG = "PagedViewWidget"; + private static final boolean DEBUG = false; + + // Temporary preset width and height of the image to keep them aligned. + //private static final int PRESET_PREVIEW_HEIGHT = 480; + //private static final int PRESET_PREVIEW_WIDTH = 480; + + private int mPresetPreviewSize; + + private static WidgetCell sShortpressTarget = null; private final Rect mOriginalImagePadding = new Rect(); @@ -53,23 +70,25 @@ public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListe private WidgetPreviewLoader mWidgetPreviewLoader; private PreviewLoadRequest mActiveRequest; - public PagedViewWidget(Context context) { + public WidgetCell(Context context) { this(context, null); } - public PagedViewWidget(Context context, AttributeSet attrs) { + public WidgetCell(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public PagedViewWidget(Context context, AttributeSet attrs, int defStyle) { + public WidgetCell(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); final Resources r = context.getResources(); mDimensionsFormatString = r.getString(R.string.widget_dims_format); + mPresetPreviewSize = r.getDimensionPixelSize(R.dimen.widget_preview_size); setWillNotDraw(false); setClipToPadding(false); setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate()); + } @Override @@ -97,8 +116,11 @@ public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListe @Override protected void onDetachedFromWindow() { + if (DEBUG) { + Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString())); + } super.onDetachedFromWindow(); - deletePreview(true); + deletePreview(false); } public void deletePreview(boolean recycleImage) { @@ -154,15 +176,19 @@ public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListe public int[] getPreviewSize() { final ImageView i = (ImageView) findViewById(R.id.widget_preview); int[] maxSize = new int[2]; - maxSize[0] = i.getWidth() - mOriginalImagePadding.left - mOriginalImagePadding.right; - maxSize[1] = i.getHeight() - mOriginalImagePadding.top; + maxSize[0] = mPresetPreviewSize; + maxSize[1] = mPresetPreviewSize; return maxSize; } public void applyPreview(Bitmap bitmap) { FastBitmapDrawable preview = new FastBitmapDrawable(bitmap); - final PagedViewWidgetImageView image = - (PagedViewWidgetImageView) findViewById(R.id.widget_preview); + final WidgetImageView image = + (WidgetImageView) findViewById(R.id.widget_preview); + if (DEBUG) { + Log.d(TAG, String.format("[tag=%s] applyPreview preview: %s", + getTagToString(), preview)); + } if (preview != null) { image.mAllowRequestLayout = false; image.setImageDrawable(preview); @@ -177,6 +203,7 @@ public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListe } image.setAlpha(1f); image.mAllowRequestLayout = true; + image.requestLayout(); } } @@ -193,8 +220,8 @@ public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListe public void run() { if (sShortpressTarget != null) return; if (mShortPressListener != null) { - mShortPressListener.onShortPress(PagedViewWidget.this); - sShortpressTarget = PagedViewWidget.this; + mShortPressListener.onShortPress(WidgetCell.this); + sShortpressTarget = WidgetCell.this; } mShortPressTriggered = true; } @@ -221,7 +248,7 @@ public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListe removeShortPressCallback(); if (mShortPressTriggered) { if (mShortPressListener != null) { - mShortPressListener.cleanUpShortPress(PagedViewWidget.this); + mShortPressListener.cleanUpShortPress(WidgetCell.this); } mShortPressTriggered = false; } @@ -264,6 +291,10 @@ public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListe return; } int[] size = getPreviewSize(); + if (DEBUG) { + Log.d(TAG, String.format("[tag=%s] ensurePreview (%d, %d):", + getTagToString(), size[0], size[1])); + } if (size[0] <= 0 || size[1] <= 0) { addOnLayoutChangeListener(this); @@ -292,4 +323,16 @@ public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListe return Math.min(size[0], info.spanX * cellWidth); } + + /** + * Helper method to get the string info of the tag. + */ + private String getTagToString() { + if (getTag() instanceof PendingAddWidgetInfo) { + return ((PendingAddWidgetInfo)getTag()).toString(); + } else if (getTag() instanceof PendingAddShortcutInfo) { + return ((PendingAddShortcutInfo)getTag()).toString(); + } + return ""; + } } diff --git a/src/com/android/launcher3/PagedViewWidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java index 7d8279547..75167bc7d 100644 --- a/src/com/android/launcher3/PagedViewWidgetImageView.java +++ b/src/com/android/launcher3/widget/WidgetImageView.java @@ -14,17 +14,17 @@ * limitations under the License. */ -package com.android.launcher3; +package com.android.launcher3.widget; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.widget.ImageView; -public class PagedViewWidgetImageView extends ImageView { +public class WidgetImageView extends ImageView { public boolean mAllowRequestLayout = true; - public PagedViewWidgetImageView(Context context, AttributeSet attrs) { + public WidgetImageView(Context context, AttributeSet attrs) { super(context, attrs); } @@ -44,6 +44,5 @@ public class PagedViewWidgetImageView extends ImageView { super.onDraw(canvas); canvas.restore(); - } } diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java new file mode 100644 index 000000000..6580ab4ff --- /dev/null +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.widget; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.android.launcher3.CellLayout; +import com.android.launcher3.DeleteDropTarget; +import com.android.launcher3.DragController; +import com.android.launcher3.DragSource; +import com.android.launcher3.DropTarget.DragObject; +import com.android.launcher3.FastBitmapDrawable; +import com.android.launcher3.Folder; +import com.android.launcher3.IconCache; +import com.android.launcher3.Insettable; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.PendingAddItemInfo; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.WidgetPreviewLoader; +import com.android.launcher3.Workspace; + +import java.util.ArrayList; + +/** + * The widgets list view container. + */ +public class WidgetsContainerView extends FrameLayout implements Insettable, View.OnTouchListener, + View.OnLongClickListener, DragSource{ + + private static final String TAG = "WidgetContainerView"; + private static final boolean DEBUG = false; + + /* {@link RecyclerView} will keep following # of views in cache, before recycling. */ + private static final int WIDGET_CACHE_SIZE = 2; + + /* Global instances that are used inside this container. */ + private Launcher mLauncher; + private DragController mDragController; + private IconCache mIconCache; + + /* Data model for the widget */ + private WidgetsModel mWidgets; + + /* Recycler view related member variables */ + private RecyclerView mView; + private WidgetsListAdapter mAdapter; + + /* Dragging related. */ + private boolean mDraggingWidget = false; // TODO(hyunyoungs): seems not needed? check! + private Point mLastTouchDownPos = new Point(); + + /* Rendering related. */ + private WidgetPreviewLoader mWidgetPreviewLoader; + private Rect mPadding = new Rect(); + + public WidgetsContainerView(Context context) { + this(context, null); + } + + public WidgetsContainerView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr); + mLauncher = (Launcher) context; + mDragController = mLauncher.getDragController(); + + mAdapter = new WidgetsListAdapter(context, this, mLauncher, this, mLauncher); + mWidgets = new WidgetsModel(context, mAdapter); + mAdapter.setWidgetsModel(mWidgets); + mIconCache = (LauncherAppState.getInstance()).getIconCache(); + + if (DEBUG) { + Log.d(TAG, "WidgetsContainerView constructor"); + } + } + + @Override + protected void onFinishInflate() { + if (DEBUG) { + Log.d(TAG, String.format("onFinishInflate [widgets size=%d]", + mWidgets.getPackageSize())); + } + mView = (RecyclerView) findViewById(R.id.widgets_list_view); + mView.setAdapter(mAdapter); + mView.setLayoutManager(new LinearLayoutManager(getContext())); + mView.setItemViewCacheSize(WIDGET_CACHE_SIZE); + + mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(), + getPaddingBottom()); + } + + // + // Returns views used for launcher transitions. + // + + public View getContentView() { + return findViewById(R.id.widgets_list_view); + } + + public View getRevealView() { + // TODO(hyunyoungs): temporarily use apps view transition. + return findViewById(R.id.widgets_reveal_view); + } + + public void scrollToTop() { + mView.scrollToPosition(0); + if (DEBUG) { + Log.d(TAG, String.format("scrollToTop, [widgets size=%d]", + mWidgets.getPackageSize())); + } + } + + // + // Touch related handling. + // + + @Override + public boolean onLongClick(View v) { + if (DEBUG) { + Log.d(TAG, String.format("onLonglick [v=%s]", v)); + } + + // Return early if this is not initiated from a touch + if (!v.isInTouchMode()) return false; + // When we have exited all apps or are in transition, disregard long clicks + if (!mLauncher.isWidgetsViewVisible() || + mLauncher.getWorkspace().isSwitchingState()) return false; + // Return if global dragging is not enabled + Log.d(TAG, String.format("onLonglick dragging enabled?.", v)); + if (!mLauncher.isDraggingEnabled()) return false; + + return beginDragging(v); + } + + private boolean beginDragging(View v) { + if (v instanceof WidgetCell) { + if (!beginDraggingWidget((WidgetCell) v)) { + return false; + } + } else { + Log.e(TAG, "Unexpected dragging view: " + v); + } + + // We delay entering spring-loaded mode slightly to make sure the UI + // thready is free of any work. + postDelayed(new Runnable() { + @Override + public void run() { + // We don't enter spring-loaded mode if the drag has been cancelled + if (mLauncher.getDragController().isDragging()) { + // Go into spring loaded mode (must happen before we startDrag()) + mLauncher.enterSpringLoadedDragMode(); + } + } + }, 150); + + return true; + } + + private boolean beginDraggingWidget(WidgetCell v) { + mDraggingWidget = true; + // Get the widget preview as the drag representation + ImageView image = (ImageView) v.findViewById(R.id.widget_preview); + PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag(); + + // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and + // we abort the drag. + if (image.getDrawable() == null) { + mDraggingWidget = false; + return false; + } + + // Compose the drag image + Bitmap preview; + Bitmap outline; + float scale = 1f; + Point previewPadding = null; + + if (createItemInfo instanceof PendingAddWidgetInfo) { + // This can happen in some weird cases involving multi-touch. We can't start dragging + // the widget if this is null, so we break out. + + PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo; + int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true); + + FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable(); + float minScale = 1.25f; + int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]); + + int[] previewSizeBeforeScale = new int[1]; + preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info, + maxWidth, null, previewSizeBeforeScale); + // Compare the size of the drag preview to the preview in the AppsCustomize tray + int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0], + v.getActualItemWidth()); + scale = previewWidthInAppsCustomize / (float) preview.getWidth(); + + // The bitmap in the AppsCustomize tray is always the the same size, so there + // might be extra pixels around the preview itself - this accounts for that + if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) { + int padding = + (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2; + previewPadding = new Point(padding, 0); + } + } else { + PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag(); + Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo); + preview = Utilities.createIconBitmap(icon, mLauncher); + createItemInfo.spanX = createItemInfo.spanY = 1; + } + + // Don't clip alpha values for the drag outline if we're using the default widget preview + boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo && + (((PendingAddWidgetInfo) createItemInfo).previewImage == 0)); + + // Save the preview for the outline generation, then dim the preview + outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(), + false); + + // Start the drag + mLauncher.lockScreenOrientation(); + mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha); + mDragController.startDrag(image, preview, this, createItemInfo, + DragController.DRAG_ACTION_COPY, previewPadding, scale); + outline.recycle(); + preview.recycle(); + return true; + } + + /* + * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent) + */ + @Override + public boolean onTouch(View v, MotionEvent ev) { + Log.d(TAG, String.format("onTouch [MotionEvent=%s]", ev)); + if (ev.getAction() == MotionEvent.ACTION_DOWN || + ev.getAction() == MotionEvent.ACTION_MOVE) { + mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY()); + } + return false; + } + + // + // Drag related handling methods that implement {@link DragSource} interface. + // + + @Override + public boolean supportsFlingToDelete() { + return false; + } + + @Override + public boolean supportsAppInfoDropTarget() { + return true; + } + + /* + * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the + * {@link DeleteDropTarget} to be invisible.) + */ + @Override + public boolean supportsDeleteDropTarget() { + return false; + } + + @Override + public float getIntrinsicIconScaleFactor() { + return 0; + } + + @Override + public void onFlingToDeleteCompleted() { + // We just dismiss the drag when we fling, so cleanup here + mLauncher.exitSpringLoadedDragModeDelayed(true, + Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null); + mLauncher.unlockScreenOrientation(false); + } + + @Override + public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete, + boolean success) { + if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() && + !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) { + // Exit spring loaded mode if we have not successfully dropped or have not handled the + // drop in Workspace + mLauncher.exitSpringLoadedDragModeDelayed(true, + Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null); + } + mLauncher.unlockScreenOrientation(false); + + // Display an error message if the drag failed due to there not being enough space on the + // target layout we were dropping on. + if (!success) { + boolean showOutOfSpaceMessage = false; + if (target instanceof Workspace) { + int currentScreen = mLauncher.getCurrentWorkspaceScreen(); + Workspace workspace = (Workspace) target; + CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen); + ItemInfo itemInfo = (ItemInfo) d.dragInfo; + if (layout != null) { + layout.calculateSpans(itemInfo); + showOutOfSpaceMessage = + !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY); + } + } + if (showOutOfSpaceMessage) { + mLauncher.showOutOfSpaceMessage(false); + } + d.deferDragViewCleanupPostAnimation = false; + } + } + + // + // Container rendering related. + // + + /* + * @see Insettable#setInsets(Rect) + */ + @Override + public void setInsets(Rect insets) { + setPadding(mPadding.left + insets.left, mPadding.top + insets.top, + mPadding.right + insets.right, mPadding.bottom + insets.bottom); + } + + /** + * Initialize the widget data model. + */ + public void addWidgets(ArrayList<Object> widgetsShortcuts, PackageManager pm) { + mWidgets.addWidgetsAndShortcuts(widgetsShortcuts, pm); + } + + private WidgetPreviewLoader getWidgetPreviewLoader() { + if (mWidgetPreviewLoader == null) { + mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache(); + } + return mWidgetPreviewLoader; + } + +}
\ No newline at end of file diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java new file mode 100644 index 000000000..d0d1e60b4 --- /dev/null +++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.widget; + +import android.content.Context; +import android.content.pm.ResolveInfo; +import android.support.v7.widget.RecyclerView.Adapter; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.launcher3.IconCache; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.R; +import com.android.launcher3.WidgetPreviewLoader; +import com.android.launcher3.compat.UserHandleCompat; + +import java.util.List; + +/** + * List view adapter for the widget tray. + * + * <p>Memory vs. Performance: + * The less number of types of views are inserted into a {@link RecyclerView}, the more recycling + * happens and less memory is consumed. {@link #getItemViewType} was not overridden as there is + * only a single type of view. + */ +public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> { + + private static final String TAG = "WidgetsListAdapter"; + private static final boolean DEBUG = false; + + private Context mContext; + private Launcher mLauncher; + private LayoutInflater mLayoutInflater; + private IconCache mIconCache; + + private WidgetsModel mWidgetsModel; + private WidgetPreviewLoader mWidgetPreviewLoader; + + private View.OnTouchListener mTouchListener; + private View.OnClickListener mIconClickListener; + private View.OnLongClickListener mIconLongClickListener; + + + public WidgetsListAdapter(Context context, + View.OnTouchListener touchListener, + View.OnClickListener iconClickListener, + View.OnLongClickListener iconLongClickListener, + Launcher launcher) { + mLayoutInflater = LayoutInflater.from(context); + mContext = context; + + mTouchListener = touchListener; + mIconClickListener = iconClickListener; + mIconLongClickListener = iconLongClickListener; + + mLauncher = launcher; + mIconCache = LauncherAppState.getInstance().getIconCache(); + } + + public void setWidgetsModel(WidgetsModel w) { + mWidgetsModel = w; + } + + @Override + public int getItemCount() { + return mWidgetsModel.getPackageSize(); + } + + @Override + public void onBindViewHolder(WidgetsRowViewHolder holder, int pos) { + String packageName = mWidgetsModel.getPackageName(pos); + List<Object> infoList = mWidgetsModel.getSortedWidgets(packageName); + + ViewGroup row = ((ViewGroup) holder.getContent().findViewById(R.id.widgets_cell_list)); + if (DEBUG) { + Log.d(TAG, String.format( + "onBindViewHolder [pos=%d, packageName=%s, widget#=%d, row.getChildCount=%d]", + pos, packageName, infoList.size(), row.getChildCount())); + } + + // Add more views. + // if there are too many, hide them. + int diff = infoList.size() - row.getChildCount(); + if (diff > 0) { + for (int i = 0; i < diff; i++) { + WidgetCell widget = new WidgetCell(mContext); + widget = (WidgetCell) mLayoutInflater.inflate( + R.layout.widget_cell, row, false); + + // set up touch. + widget.setOnClickListener(mIconClickListener); + widget.setOnLongClickListener(mIconLongClickListener); + widget.setOnTouchListener(mTouchListener); + row.addView(widget); + } + } else if (diff < 0) { + for (int i=infoList.size() ; i < row.getChildCount(); i++) { + row.getChildAt(i).setVisibility(View.GONE); + } + } + + // Bind the views in the application info section. + PackageItemInfo infoOut = mWidgetsModel.getPackageItemInfo(packageName); + if (infoOut.usingLowResIcon) { + mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(), + false /* useLowResIcon */, infoOut); + } + ((TextView) holder.getContent().findViewById(R.id.section)).setText(infoOut.title); + ImageView iv = (ImageView) holder.getContent().findViewById(R.id.section_image); + iv.setImageBitmap(infoOut.iconBitmap); + + // Bind the view in the widget horizontal tray region. + for (int i=0; i < infoList.size(); i++) { + WidgetCell widget = (WidgetCell) row.getChildAt(i); + if (getWidgetPreviewLoader() == null || widget == null) { + return; + } + if (infoList.get(i) instanceof LauncherAppWidgetProviderInfo) { + LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) infoList.get(i); + PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(info, null); + widget.setTag(pawi); + widget.applyFromAppWidgetProviderInfo(info, -1, mWidgetPreviewLoader); + } else if (infoList.get(i) instanceof ResolveInfo) { + ResolveInfo info = (ResolveInfo) infoList.get(i); + PendingAddShortcutInfo pasi = new PendingAddShortcutInfo(info.activityInfo); + widget.setTag(pasi); + widget.applyFromResolveInfo(mLauncher.getPackageManager(), info, mWidgetPreviewLoader); + } + widget.setVisibility(View.VISIBLE); + widget.ensurePreview(); + } + // TODO(hyunyoungs): Draw the scrollable indicator. + } + + @Override + public WidgetsRowViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (DEBUG) { + Log.v(TAG, String.format("\nonCreateViewHolder, [widget#=%d]", viewType)); + } + + ViewGroup container = (ViewGroup) mLayoutInflater.inflate( + R.layout.widgets_list_row_view, parent, false); + return new WidgetsRowViewHolder(container); + } + + @Override + public long getItemId(int pos) { + return pos; + } + + private WidgetPreviewLoader getWidgetPreviewLoader() { + if (mWidgetPreviewLoader == null) { + mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache(); + } + return mWidgetPreviewLoader; + } + + /** + * TODO(hyunyoungs): this is temporary. Figure out the width of each widget cell + * and then check if the total sum is longer than the parent width. + */ + private void addScrollableIndicator(int contentSize, ViewGroup parent) { + if (contentSize > 2) { + ViewGroup indicator = (ViewGroup) parent.findViewById(R.id.scrollable_indicator); + indicator.setVisibility(View.VISIBLE); + } + } +} diff --git a/src/com/android/launcher3/widget/WidgetsModel.java b/src/com/android/launcher3/widget/WidgetsModel.java new file mode 100644 index 000000000..c400d6366 --- /dev/null +++ b/src/com/android/launcher3/widget/WidgetsModel.java @@ -0,0 +1,136 @@ + +package com.android.launcher3.widget; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.support.v7.widget.RecyclerView; +import android.util.Log; + +import com.android.launcher3.IconCache; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.LauncherModel.WidgetAndShortcutNameComparator; +import com.android.launcher3.compat.UserHandleCompat; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Widgets data model that is used by the adapters of the widget views and controllers. + * + * <p> The widgets and shortcuts are organized using package name as its index. + */ +public class WidgetsModel { + + private static final String TAG = "WidgetsModel"; + private static final boolean DEBUG = false; + + /* List of packages that is tracked by this model. */ + private List<String> mPackageNames = new ArrayList<>(); + + private Map<String, PackageItemInfo> mPackageItemInfoList = new HashMap<>(); + + /* Map of widgets and shortcuts that are tracked per package. */ + private Map<String, ArrayList<Object>> mWidgetsList = new HashMap<>(); + + /* Notifies the adapter when data changes. */ + private RecyclerView.Adapter mAdapter; + + private Comparator mWidgetAndShortcutNameComparator; + + private IconCache mIconCache; + + public WidgetsModel(Context context, RecyclerView.Adapter adapter) { + mAdapter = adapter; + mWidgetAndShortcutNameComparator = new WidgetAndShortcutNameComparator(context); + mIconCache = LauncherAppState.getInstance().getIconCache(); + } + + // Access methods that may be deleted if the private fields are made package-private. + public int getPackageSize() { + return mPackageNames.size(); + } + + // Access methods that may be deleted if the private fields are made package-private. + public String getPackageName(int pos) { + return mPackageNames.get(pos); + } + + public PackageItemInfo getPackageItemInfo(String packageName) { + return mPackageItemInfoList.get(packageName); + } + + public List<Object> getSortedWidgets(String packageName) { + return mWidgetsList.get(packageName); + } + + public void addWidgetsAndShortcuts(ArrayList<Object> widgetsShortcuts, PackageManager pm) { + if (DEBUG) { + Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + widgetsShortcuts.size()); + } + + // clear the lists. + mPackageNames.clear(); + mWidgetsList.clear(); + + // add and update. + for (Object o: widgetsShortcuts) { + String packageName = ""; + if (o instanceof LauncherAppWidgetProviderInfo) { + LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o; + packageName = widgetInfo.provider.getPackageName(); + } else if (o instanceof ResolveInfo) { + ResolveInfo resolveInfo = (ResolveInfo) o; + packageName = resolveInfo.activityInfo.packageName; + } else { + Log.e(TAG, String.format("addWidgetsAndShortcuts, nothing added for class=%s", + o.getClass().toString())); + + } + + ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(packageName); + if (widgetsShortcutsList != null) { + widgetsShortcutsList.add(o); + } else { + widgetsShortcutsList = new ArrayList<Object>(); + widgetsShortcutsList.add(o); + mWidgetsList.put(packageName, widgetsShortcutsList); + mPackageNames.add(packageName); + } + } + for (String packageName: mPackageNames) { + PackageItemInfo pInfo = mPackageItemInfoList.get(packageName); + if (pInfo == null) { + pInfo = new PackageItemInfo(); + mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(), + true /* useLowResIcon */, pInfo); + mPackageItemInfoList.put(packageName, pInfo); + } + } + + // sort. + sortPackageList(); + for (String packageName: mPackageNames) { + Collections.sort(mWidgetsList.get(packageName), mWidgetAndShortcutNameComparator); + } + + // notify. + mAdapter.notifyDataSetChanged(); + } + + private void sortPackageList() { + Collections.sort(mPackageNames, new Comparator<String>() { + @Override + public int compare(String lhs, String rhs) { + String lhsTitle = mPackageItemInfoList.get(lhs).title.toString(); + String rhsTitle = mPackageItemInfoList.get(rhs).title.toString(); + return lhsTitle.compareTo(rhsTitle); + } + }); + } +} diff --git a/src/com/android/launcher3/PagedViewGridLayout.java b/src/com/android/launcher3/widget/WidgetsRowView.java index f69fa562d..54667384b 100644 --- a/src/com/android/launcher3/PagedViewGridLayout.java +++ b/src/com/android/launcher3/widget/WidgetsRowView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,36 +14,31 @@ * limitations under the License. */ -package com.android.launcher3; +package com.android.launcher3.widget; import android.content.Context; import android.view.MotionEvent; -import android.view.View; import android.widget.FrameLayout; -import android.widget.GridLayout; +import android.widget.HorizontalScrollView; +import android.widget.TextView; + +import com.android.launcher3.R; /** - * The grid based layout used strictly for the widget/wallpaper tab of the AppsCustomize pane + * Layout used for widget tray rows for each app. For performance, this view can be replaced with + * a {@link RecyclerView} in the future if we settle on scrollable single row for the widgets. + * If we decide on collapsable grid, then HorizontalScrollView can be replaced with a + * {@link GridLayout}. */ -public class PagedViewGridLayout extends GridLayout implements Page { - static final String TAG = "PagedViewGridLayout"; +public class WidgetsRowView extends HorizontalScrollView { + static final String TAG = "WidgetsRow"; - private int mCellCountX; - private int mCellCountY; private Runnable mOnLayoutListener; + private String mAppName; - public PagedViewGridLayout(Context context, int cellCountX, int cellCountY) { + public WidgetsRowView(Context context, String appName) { super(context, null, 0); - mCellCountX = cellCountX; - mCellCountY = cellCountY; - } - - int getCellCountX() { - return mCellCountX; - } - - int getCellCountY() { - return mCellCountY; + mAppName = appName; } /** @@ -57,6 +52,13 @@ public class PagedViewGridLayout extends GridLayout implements Page { } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + TextView tv = (TextView) findViewById(R.id.widget_name); + tv.setText(mAppName); + } + + @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mOnLayoutListener = null; @@ -66,6 +68,7 @@ public class PagedViewGridLayout extends GridLayout implements Page { mOnLayoutListener = r; } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (mOnLayoutListener != null) { @@ -76,43 +79,9 @@ public class PagedViewGridLayout extends GridLayout implements Page { @Override public boolean onTouchEvent(MotionEvent event) { boolean result = super.onTouchEvent(event); - int count = getPageChildCount(); - if (count > 0) { - // We only intercept the touch if we are tapping in empty space after the final row - View child = getChildOnPageAt(count - 1); - int bottom = child.getBottom(); - result = result || (event.getY() < bottom); - } return result; } - @Override - public void removeAllViewsOnPage() { - removeAllViews(); - mOnLayoutListener = null; - setLayerType(LAYER_TYPE_NONE, null); - } - - @Override - public void removeViewOnPageAt(int index) { - removeViewAt(index); - } - - @Override - public int getPageChildCount() { - return getChildCount(); - } - - @Override - public View getChildOnPageAt(int i) { - return getChildAt(i); - } - - @Override - public int indexOfChildOnPage(View v) { - return indexOfChild(v); - } - public static class LayoutParams extends FrameLayout.LayoutParams { public LayoutParams(int width, int height) { super(width, height); diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java new file mode 100644 index 000000000..99a192c89 --- /dev/null +++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.widget; + +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +public class WidgetsRowViewHolder extends ViewHolder { + + ViewGroup mContent; + + public WidgetsRowViewHolder(ViewGroup v) { + super(v); + mContent = v; + } + + ViewGroup getContent() { + return mContent; + } +} |