WidgetTray revamp work
- RecyclerView is rendering - Animation is connected - Drag and drop is now handled - UI tweaking: background, margins, more to come. - Flicker and preview not loading issue: fixed height for the horizontal scroll view. - Shortcuts are added - Widget Preview loading should support shortPress for drop - UI tweaks left: overlay of arrow when there are more items to scroll - icons are added in the section header - Sorting of widget sections and widget horizontal list - Adding all the padding constants to dimen.xml file - RecyclerView should only support one view type For items to be addressed in follow up patches OR CLs, TODO is added to the comment. b/19897708 Change-Id: Ibfc4da1696a23d20bada93db46e126706eb13cdc
This commit is contained in:
parent
85e3d4cc5e
commit
3f471440a8
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
|
|||
return mModel;
|
||||
}
|
||||
|
||||
LauncherAccessibilityDelegate getAccessibilityDelegate() {
|
||||
public LauncherAccessibilityDelegate getAccessibilityDelegate() {
|
||||
return mAccessibilityDelegate;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,44 +494,8 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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 "";
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,6 +51,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();
|
||||
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue