summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2015-03-02 11:51:23 -0800
committerWinson Chung <winsonc@google.com>2015-03-10 18:14:22 -0700
commitb745afbdd75157c73d581b345118cdaff99e912d (patch)
treedb80cffb7504c9897e91f39243207776f43556c0
parent434e667b5b488d6212e8c77c8ad3b02c4af37117 (diff)
downloadandroid_packages_apps_Trebuchet-b745afbdd75157c73d581b345118cdaff99e912d.tar.gz
android_packages_apps_Trebuchet-b745afbdd75157c73d581b345118cdaff99e912d.tar.bz2
android_packages_apps_Trebuchet-b745afbdd75157c73d581b345118cdaff99e912d.zip
Initial changes to break out AllApps into its own view.
- Moves launcher state-transition code into its own class - Moves all-apps related code into a separate view/set of classes - Implements a basic list view for all apps Change-Id: I68f174aa9e1bf82c4e46ce9549c78a8dc4623f46
-rw-r--r--res/drawable/apps_list_bg.xml21
-rw-r--r--res/layout-land/launcher.xml6
-rw-r--r--res/layout-port/launcher.xml6
-rw-r--r--res/layout-sw600dp/apps_view.xml34
-rw-r--r--res/layout-sw720dp/launcher.xml6
-rw-r--r--res/layout/apps_grid_row_icon_view.xml22
-rw-r--r--res/layout/apps_grid_row_view.xml38
-rw-r--r--res/layout/apps_list_reveal_view.xml25
-rw-r--r--res/layout/apps_list_row_icon_view.xml28
-rw-r--r--res/layout/apps_list_row_view.xml34
-rw-r--r--res/layout/apps_list_view.xml30
-rw-r--r--res/layout/apps_view.xml28
-rw-r--r--res/values-sw600dp/dimens.xml3
-rw-r--r--res/values/attrs.xml8
-rw-r--r--res/values/dimens.xml3
-rw-r--r--src/com/android/launcher3/AppsContainerView.java609
-rw-r--r--src/com/android/launcher3/AppsCustomizePagedView.java219
-rw-r--r--src/com/android/launcher3/AppsCustomizeTabHost.java44
-rw-r--r--src/com/android/launcher3/BubbleTextView.java101
-rw-r--r--src/com/android/launcher3/DeviceProfile.java2
-rw-r--r--src/com/android/launcher3/Folder.java4
-rw-r--r--src/com/android/launcher3/Launcher.java781
-rw-r--r--src/com/android/launcher3/LauncherModel.java2
-rw-r--r--src/com/android/launcher3/LauncherStateTransitionAnimation.java832
-rw-r--r--src/com/android/launcher3/PagedViewWithDraggableItems.java2
-rw-r--r--src/com/android/launcher3/WidgetPreviewLoader.java4
-rw-r--r--src/com/android/launcher3/WidgetsContainerView.java88
-rw-r--r--src/com/android/launcher3/Workspace.java67
28 files changed, 2112 insertions, 935 deletions
diff --git a/res/drawable/apps_list_bg.xml b/res/drawable/apps_list_bg.xml
new file mode 100644
index 000000000..61f1c083a
--- /dev/null
+++ b/res/drawable/apps_list_bg.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="#ffffff" />
+ <corners android:radius="3dp" />
+</shape> \ No newline at end of file
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 6f95bd506..b13984a26 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -62,6 +62,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
+
+ <include layout="@layout/apps_view"
+ android:id="@+id/apps_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index af30a32e5..3cb338efe 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -71,6 +71,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
+
+ <include layout="@layout/apps_view"
+ android:id="@+id/apps_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
diff --git a/res/layout-sw600dp/apps_view.xml b/res/layout-sw600dp/apps_view.xml
new file mode 100644
index 000000000..1f773b307
--- /dev/null
+++ b/res/layout-sw600dp/apps_view.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<com.android.launcher3.AppsContainerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/apps_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="8dp"
+ android:background="#22000000"
+ android:descendantFocusability="afterDescendants">
+ <include
+ layout="@layout/apps_list_reveal_view"
+ android:layout_width="420dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+ <include
+ layout="@layout/apps_list_view"
+ android:layout_width="420dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+</com.android.launcher3.AppsContainerView> \ No newline at end of file
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 960ccf330..a3d502cf4 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -71,6 +71,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
+
+ <include layout="@layout/apps_view"
+ android:id="@+id/apps_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible" />
</com.android.launcher3.DragLayer>
<ViewStub
diff --git a/res/layout/apps_grid_row_icon_view.xml b/res/layout/apps_grid_row_icon_view.xml
new file mode 100644
index 000000000..11c8eeb4d
--- /dev/null
+++ b/res/layout/apps_grid_row_icon_view.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<com.android.launcher3.BubbleTextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/WorkspaceIcon.AppsCustomize"
+ android:id="@+id/application_icon"
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout/apps_grid_row_view.xml b/res/layout/apps_grid_row_view.xml
new file mode 100644
index 000000000..bce43bc1b
--- /dev/null
+++ b/res/layout/apps_grid_row_view.xml
@@ -0,0 +1,38 @@
+<?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:layout_width="match_parent"
+ android:layout_height="@dimen/apps_view_row_height"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:orientation="horizontal"
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg"
+ android:descendantFocusability="afterDescendants">
+ <TextView
+ android:id="@+id/section"
+ android:layout_width="48dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingRight="8dp"
+ android:paddingBottom="12dp"
+ android:gravity="right"
+ android:textColor="#1ca195"
+ android:textSize="16sp"
+ android:textAllCaps="true"
+ android:focusable="false" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/apps_list_reveal_view.xml b/res/layout/apps_list_reveal_view.xml
new file mode 100644
index 000000000..4a26787c8
--- /dev/null
+++ b/res/layout/apps_list_reveal_view.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/all_apps_transition_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:elevation="15dp"
+ android:visibility="invisible"
+ android:background="@drawable/apps_list_bg"
+ android:focusable="false" /> \ No newline at end of file
diff --git a/res/layout/apps_list_row_icon_view.xml b/res/layout/apps_list_row_icon_view.xml
new file mode 100644
index 000000000..607af9b0b
--- /dev/null
+++ b/res/layout/apps_list_row_icon_view.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<com.android.launcher3.BubbleTextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ style="@style/WorkspaceIcon.AppsCustomize"
+ android:id="@+id/application_icon"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg"
+ launcher:iconPaddingOverride="24dp"
+ launcher:textSizeOverride="16dp"
+ launcher:layoutHorizontal="true" />
diff --git a/res/layout/apps_list_row_view.xml b/res/layout/apps_list_row_view.xml
new file mode 100644
index 000000000..c4dcd0018
--- /dev/null
+++ b/res/layout/apps_list_row_view.xml
@@ -0,0 +1,34 @@
+<?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:layout_width="match_parent"
+ android:layout_height="@dimen/apps_view_row_height"
+ android:orientation="horizontal"
+ android:focusable="true"
+ android:background="@drawable/focusable_view_bg"
+ android:descendantFocusability="afterDescendants">
+ <TextView
+ android:id="@+id/section"
+ android:layout_width="64dp"
+ android:layout_height="match_parent"
+ android:paddingLeft="16dp"
+ android:gravity="left|center_vertical"
+ android:textColor="#009688"
+ android:textSize="24sp"
+ android:textAllCaps="true"
+ android:focusable="false" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/apps_list_view.xml b/res/layout/apps_list_view.xml
new file mode 100644
index 000000000..b1b0f310b
--- /dev/null
+++ b/res/layout/apps_list_view.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<ListView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/apps_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:clipToPadding="false"
+ android:scrollbars="vertical"
+ android:elevation="15dp"
+ android:background="@drawable/apps_list_bg"
+ android:visibility="gone"
+ android:focusable="true"
+ android:descendantFocusability="afterDescendants" /> \ No newline at end of file
diff --git a/res/layout/apps_view.xml b/res/layout/apps_view.xml
new file mode 100644
index 000000000..19ad3d2c9
--- /dev/null
+++ b/res/layout/apps_view.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<com.android.launcher3.AppsContainerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/apps_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="8dp"
+ android:background="#22000000"
+ android:descendantFocusability="afterDescendants">
+ <include
+ layout="@layout/apps_list_reveal_view" />
+ <include
+ layout="@layout/apps_list_view" />
+</com.android.launcher3.AppsContainerView> \ No newline at end of file
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 28679be2e..f7ad0c4cd 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -17,6 +17,9 @@
<resources>
<dimen name="app_icon_size">64dp</dimen>
+<!-- Apps view -->
+ <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>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 3331cdec4..4e7c59280 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -18,6 +18,14 @@
<resources>
+ <!-- BubbleTextView specific attributes. -->
+ <declare-styleable name="BubbleTextView">
+ <attr name="layoutHorizontal" format="boolean" />
+ <attr name="iconSizeOverride" format="dimension" />
+ <attr name="iconPaddingOverride" format="dimension" />
+ <attr name="textSizeOverride" format="dimension" />
+ </declare-styleable>
+
<!-- Page Indicator specific attributes. -->
<declare-styleable name="PageIndicator">
<attr name="windowSize" format="integer" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d6fc508d1..013bd925b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -46,6 +46,9 @@
<dimen name="toolbar_button_vertical_padding">4dip</dimen>
<dimen name="toolbar_button_horizontal_padding">12dip</dimen>
+<!-- Apps view -->
+ <dimen name="apps_view_row_height">64dp</dimen>
+
<!-- AllApps/Customize/AppsCustomize -->
<!-- The height of the tab bar - if this changes, we should update the
external icon width/height above to compensate -->
diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java
new file mode 100644
index 000000000..cabacec3c
--- /dev/null
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -0,0 +1,609 @@
+package com.android.launcher3;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.SectionIndexer;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Represents a row in the apps list view.
+ */
+class AppsRow {
+ int sectionId;
+ String sectionDescription;
+ List<AppInfo> apps;
+
+ public AppsRow(int sId, String sc, List<AppInfo> ai) {
+ sectionId = sId;
+ sectionDescription = sc;
+ apps = ai;
+ }
+
+ public AppsRow(int sId, List<AppInfo> ai) {
+ sectionId = sId;
+ apps = ai;
+ }
+}
+
+/**
+ * An interface to an algorithm that generates app rows.
+ */
+interface AppRowAlgorithm {
+ public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow);
+ public int getIconViewLayoutId();
+ public int getRowViewLayoutId();
+ public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info);
+}
+
+/**
+ * Computes the rows in the apps list view.
+ */
+class SectionedAppsAlgorithm implements AppRowAlgorithm {
+
+ @Override
+ public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow) {
+ List<AppsRow> rows = new ArrayList<>();
+ LinkedHashMap<String, List<AppInfo>> sections = computeSectionedApps(sortedApps);
+ int sectionId = 0;
+ for (Map.Entry<String, List<AppInfo>> sectionEntry : sections.entrySet()) {
+ String section = sectionEntry.getKey();
+ List<AppInfo> apps = sectionEntry.getValue();
+ int numRows = (int) Math.ceil((float) apps.size() / appsPerRow);
+ for (int i = 0; i < numRows; i++) {
+ List<AppInfo> appsInRow = new ArrayList<>();
+ int offset = i * appsPerRow;
+ for (int j = 0; j < appsPerRow; j++) {
+ if (offset + j < apps.size()) {
+ appsInRow.add(apps.get(offset + j));
+ }
+ }
+ if (i == 0) {
+ rows.add(new AppsRow(sectionId, section, appsInRow));
+ } else {
+ rows.add(new AppsRow(sectionId, appsInRow));
+ }
+ }
+ sectionId++;
+ }
+ return rows;
+ }
+
+ @Override
+ public int getIconViewLayoutId() {
+ return R.layout.apps_grid_row_icon_view;
+ }
+
+ @Override
+ public int getRowViewLayoutId() {
+ return R.layout.apps_grid_row_view;
+ }
+
+ private LinkedHashMap<String, List<AppInfo>> computeSectionedApps(List<AppInfo> sortedApps) {
+ LinkedHashMap<String, List<AppInfo>> sections = new LinkedHashMap<>();
+ for (AppInfo info : sortedApps) {
+ String section = getSection(info);
+ List<AppInfo> sectionApps = sections.get(section);
+ if (sectionApps == null) {
+ sectionApps = new ArrayList<>();
+ sections.put(section, sectionApps);
+ }
+ sectionApps.add(info);
+ }
+ return sections;
+ }
+
+ @Override
+ public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info) {
+ icon.applyFromApplicationInfo(info);
+ }
+
+ private String getSection(AppInfo app) {
+ return app.title.toString().substring(0, 1).toLowerCase();
+ }
+}
+
+/**
+ * Computes the rows in the apps grid view.
+ */
+class ListedAppsAlgorithm implements AppRowAlgorithm {
+
+ @Override
+ public List<AppsRow> computeAppRows(List<AppInfo> sortedApps, int appsPerRow) {
+ List<AppsRow> rows = new ArrayList<>();
+ int sectionId = -1;
+ String prevSection = "";
+ for (AppInfo info : sortedApps) {
+ List<AppInfo> appsInRow = new ArrayList<>();
+ appsInRow.add(info);
+ String section = getSection(info);
+ if (!prevSection.equals(section)) {
+ prevSection = section;
+ sectionId++;
+ rows.add(new AppsRow(sectionId, section, appsInRow));
+ } else {
+ rows.add(new AppsRow(sectionId, appsInRow));
+ }
+ }
+ return rows;
+ }
+
+ @Override
+ public int getIconViewLayoutId() {
+ return R.layout.apps_list_row_icon_view;
+ }
+
+ @Override
+ public int getRowViewLayoutId() {
+ return R.layout.apps_list_row_view;
+ }
+
+ @Override
+ public void bindRowViewIconToInfo(BubbleTextView icon, AppInfo info) {
+ icon.applyFromApplicationInfo(info);
+ }
+
+ private String getSection(AppInfo app) {
+ return app.title.toString().substring(0, 1).toLowerCase();
+ }
+}
+
+/**
+ * The adapter of all the apps
+ */
+class AppsListAdapter extends BaseAdapter implements SectionIndexer {
+
+ private LayoutInflater mLayoutInflater;
+ private List<AppsRow> mAppRows = new ArrayList<>();
+ private View.OnTouchListener mTouchListener;
+ private View.OnClickListener mIconClickListener;
+ private View.OnLongClickListener mIconLongClickListener;
+ private AppRowAlgorithm mRowAlgorithm;
+ private int mAppsPerRow;
+
+ public AppsListAdapter(Context context, View.OnTouchListener touchListener,
+ View.OnClickListener iconClickListener, View.OnLongClickListener iconLongClickListener) {
+ mLayoutInflater = LayoutInflater.from(context);
+ mTouchListener = touchListener;
+ mIconClickListener = iconClickListener;
+ mIconLongClickListener = iconLongClickListener;
+ }
+
+ void setApps(List<AppsRow> apps, int appsPerRow, AppRowAlgorithm algo) {
+ mAppsPerRow = appsPerRow;
+ mRowAlgorithm = algo;
+ mAppRows.clear();
+ mAppRows.addAll(apps);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mAppRows.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mAppRows.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ AppsRow info = mAppRows.get(position);
+ ViewGroup row = (ViewGroup) convertView;
+ if (row == null) {
+ // Inflate the row and all the icon children necessary
+ row = (ViewGroup) mLayoutInflater.inflate(mRowAlgorithm.getRowViewLayoutId(),
+ parent, false);
+ for (int i = 0; i < mAppsPerRow; i++) {
+ BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
+ mRowAlgorithm.getIconViewLayoutId(), row, false);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0,
+ ViewGroup.LayoutParams.WRAP_CONTENT, 1);
+ lp.gravity = Gravity.CENTER_VERTICAL;
+ icon.setLayoutParams(lp);
+ icon.setOnTouchListener(mTouchListener);
+ icon.setOnClickListener(mIconClickListener);
+ icon.setOnLongClickListener(mIconLongClickListener);
+ icon.setFocusable(true);
+ row.addView(icon);
+ }
+ }
+ // Bind the section header
+ TextView tv = (TextView) row.findViewById(R.id.section);
+ if (info.sectionDescription != null) {
+ tv.setText(info.sectionDescription);
+ tv.setVisibility(View.VISIBLE);
+ } else {
+ tv.setVisibility(View.INVISIBLE);
+ }
+ // Bind the icons
+ for (int i = 0; i < mAppsPerRow; i++) {
+ BubbleTextView icon = (BubbleTextView) row.getChildAt(i + 1);
+ if (i < info.apps.size()) {
+ mRowAlgorithm.bindRowViewIconToInfo(icon, info.apps.get(i));
+ icon.setVisibility(View.VISIBLE);
+ } else {
+ icon.setVisibility(View.INVISIBLE);
+ }
+ }
+ return row;
+ }
+
+ @Override
+ public Object[] getSections() {
+ ArrayList<Object> sections = new ArrayList<>();
+ int prevSectionId = -1;
+ for (AppsRow row : mAppRows) {
+ if (row.sectionId != prevSectionId) {
+ sections.add(row.sectionDescription.toUpperCase());
+ prevSectionId = row.sectionId;
+ }
+ }
+ return sections.toArray();
+ }
+
+ @Override
+ public int getPositionForSection(int sectionIndex) {
+ for (int i = 0; i < mAppRows.size(); i++) {
+ AppsRow row = mAppRows.get(i);
+ if (row.sectionId == sectionIndex) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int getSectionForPosition(int position) {
+ return mAppRows.get(position).sectionId;
+ }
+}
+
+/**
+ * The alphabetically sorted list of applications.
+ */
+class AlphabeticalAppList {
+
+ /**
+ * Callbacks for when this list is modified.
+ */
+ public interface Callbacks {
+ public void onAppsUpdated();
+ }
+
+ private List<AppInfo> mApps;
+ private Callbacks mCb;
+
+ public AlphabeticalAppList(Callbacks cb) {
+ mCb = cb;
+ }
+
+ /**
+ * Returns the list of applications.
+ */
+ public List<AppInfo> getApps() {
+ return mApps;
+ }
+
+ /**
+ * Sets the current set of apps.
+ */
+ public void setApps(List<AppInfo> apps) {
+ Collections.sort(apps, LauncherModel.getAppNameComparator());
+ mApps = apps;
+ mCb.onAppsUpdated();
+ }
+
+ /**
+ * Adds new apps to the list.
+ */
+ public void addApps(List<AppInfo> apps) {
+ // We add it in place, in alphabetical order
+ Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
+ for (AppInfo info : apps) {
+ // This call will return the exact index of where the item is if >= 0, or the index
+ // where it should be inserted if < 0.
+ int index = Collections.binarySearch(mApps, info, appNameComparator);
+ if (index < 0) {
+ mApps.add(-(index + 1), info);
+ }
+ }
+ mCb.onAppsUpdated();
+ }
+
+ /**
+ * Updates existing apps in the list
+ */
+ public void updateApps(List<AppInfo> apps) {
+ Comparator<AppInfo> appNameComparator = LauncherModel.getAppNameComparator();
+ for (AppInfo info : apps) {
+ int index = mApps.indexOf(info);
+ if (index != -1) {
+ mApps.set(index, info);
+ } else {
+ index = Collections.binarySearch(mApps, info, appNameComparator);
+ if (index < 0) {
+ mApps.add(-(index + 1), info);
+ }
+ }
+ }
+ mCb.onAppsUpdated();
+ }
+
+ /**
+ * Removes some apps from the list.
+ */
+ public void removeApps(List<AppInfo> apps) {
+ for (AppInfo info : apps) {
+ int removeIndex = findAppByComponent(mApps, info);
+ if (removeIndex != -1) {
+ mApps.remove(removeIndex);
+ }
+ }
+ mCb.onAppsUpdated();
+ }
+
+ /**
+ * Finds the index of an app given a target AppInfo.
+ */
+ private int findAppByComponent(List<AppInfo> apps, AppInfo targetInfo) {
+ ComponentName targetComponent = targetInfo.intent.getComponent();
+ int length = apps.size();
+ for (int i = 0; i < length; ++i) {
+ AppInfo info = apps.get(i);
+ if (info.user.equals(info.user)
+ && info.intent.getComponent().equals(targetComponent)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+}
+
+/**
+ * The all apps list view container.
+ */
+public class AppsContainerView extends FrameLayout implements DragSource, View.OnTouchListener,
+ View.OnLongClickListener, Insettable, AlphabeticalAppList.Callbacks {
+
+ static final int GRID_LAYOUT = 0;
+ static final int LIST_LAYOUT = 1;
+ static final int USE_LAYOUT = LIST_LAYOUT;
+
+ private Launcher mLauncher;
+ private AppRowAlgorithm mAppRowsAlgorithm;
+ private AppsListAdapter mAdapter;
+ private AlphabeticalAppList mApps;
+ private ListView mList;
+ private int mAppsRowSize;
+ private Point mLastTouchDownPos = new Point();
+ private Rect mPadding = new Rect();
+
+ public AppsContainerView(Context context) {
+ this(context, null);
+ }
+
+ public AppsContainerView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public AppsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+
+ mLauncher = (Launcher) context;
+ if (USE_LAYOUT == GRID_LAYOUT) {
+ mAppRowsAlgorithm = new SectionedAppsAlgorithm();
+ mAppsRowSize = grid.allAppsRowsSize;
+ } else if (USE_LAYOUT == LIST_LAYOUT) {
+ mAppRowsAlgorithm = new ListedAppsAlgorithm();
+ mAppsRowSize = 1;
+ }
+ mAdapter = new AppsListAdapter(context, this, mLauncher, this);
+ mApps = new AlphabeticalAppList(this);
+ }
+
+ /**
+ * Sets the current set of apps.
+ */
+ public void setApps(List<AppInfo> apps) {
+ mApps.setApps(apps);
+ }
+
+ /**
+ * Adds new apps to the list.
+ */
+ public void addApps(List<AppInfo> apps) {
+ mApps.addApps(apps);
+ }
+
+ /**
+ * Updates existing apps in the list
+ */
+ public void updateApps(List<AppInfo> apps) {
+ mApps.updateApps(apps);
+ }
+
+ /**
+ * Removes some apps from the list.
+ */
+ public void removeApps(List<AppInfo> apps) {
+ mApps.removeApps(apps);
+ }
+
+ /**
+ * Scrolls this list view to the top.
+ */
+ public void scrollToTop() {
+ mList.scrollTo(0, 0);
+ }
+
+ /**
+ * Returns the content view used for the launcher transitions.
+ */
+ public View getContentView() {
+ return findViewById(R.id.apps_list);
+ }
+
+ /**
+ * Returns the reveal view used for the launcher transitions.
+ */
+ public View getRevealView() {
+ return findViewById(R.id.all_apps_transition_overlay);
+ }
+
+ @Override
+ public void onAppsUpdated() {
+ List<AppsRow> rows = mAppRowsAlgorithm.computeAppRows(mApps.getApps(), mAppsRowSize);
+ mAdapter.setApps(rows, mAppsRowSize, mAppRowsAlgorithm);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mList = (ListView) findViewById(R.id.apps_list);
+ mList.setFastScrollEnabled(true);
+ mList.setFastScrollAlwaysVisible(true);
+ mList.setItemsCanFocus(true);
+ mList.setAdapter(mAdapter);
+ mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
+ mPadding.right + insets.right, mPadding.bottom + insets.bottom);
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN ||
+ event.getAction() == MotionEvent.ACTION_MOVE) {
+ mLastTouchDownPos.set((int) event.getX(), (int) event.getY());
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onLongClick(View 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.isAppsViewVisible() ||
+ mLauncher.getWorkspace().isSwitchingState()) return false;
+ // Return if global dragging is not enabled
+ if (!mLauncher.isDraggingEnabled()) return false;
+
+ // Start the drag
+ mLauncher.getWorkspace().beginDragShared(v, mLastTouchDownPos, this, false);
+
+ // 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 false;
+ }
+
+ @Override
+ public boolean supportsFlingToDelete() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsAppInfoDropTarget() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsDeleteDropTarget() {
+ return true;
+ }
+
+ @Override
+ public float getIntrinsicIconScaleFactor() {
+ LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+ return (float) grid.allAppsIconSizePx / grid.iconSizePx;
+ }
+
+ @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, DropTarget.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;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index 9f8d499eb..bf368125f 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -149,10 +149,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
* The different content types that this paged view can show.
*/
public enum ContentType {
- Applications,
Widgets
}
- private ContentType mContentType = ContentType.Applications;
+ private ContentType mContentType = ContentType.Widgets;
// Refs
private Launcher mLauncher;
@@ -164,7 +163,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
private int mSaveInstanceStateItemIndex = -1;
// Content
- private ArrayList<AppInfo> mApps;
private ArrayList<Object> mWidgets;
// Caching
@@ -174,9 +172,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
private int mContentWidth, mContentHeight;
private int mWidgetCountX, mWidgetCountY;
private PagedViewCellLayout mWidgetSpacingLayout;
- private int mNumAppsPages;
private int mNumWidgetPages;
- private Rect mAllAppsPadding = new Rect();
// Previews & outlines
ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
@@ -214,10 +210,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
super(context, attrs);
mLayoutInflater = LayoutInflater.from(context);
mPackageManager = context.getPackageManager();
- mApps = new ArrayList<AppInfo>();
- mWidgets = new ArrayList<Object>();
+ mWidgets = new ArrayList<>();
mIconCache = (LauncherAppState.getInstance()).getIconCache();
- mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
+ mRunningTasks = new ArrayList<>();
// Save the default widget preview background
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
@@ -256,10 +251,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
grid.edgeMarginPx, 2 * grid.edgeMarginPx);
}
- void setAllAppsPadding(Rect r) {
- mAllAppsPadding.set(r);
- }
-
void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) {
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight);
}
@@ -277,22 +268,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int i = -1;
if (getPageCount() > 0) {
int currentPage = getCurrentPage();
- if (mContentType == ContentType.Applications) {
- AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(currentPage);
- ShortcutAndWidgetContainer childrenLayout = layout.getShortcutsAndWidgets();
- int numItemsPerPage = mCellCountX * mCellCountY;
- int childCount = childrenLayout.getChildCount();
- if (childCount > 0) {
- i = (currentPage * numItemsPerPage) + (childCount / 2);
- }
- } else if (mContentType == ContentType.Widgets) {
- int numApps = mApps.size();
+ if (mContentType == ContentType.Widgets) {
PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
int numItemsPerPage = mWidgetCountX * mWidgetCountY;
int childCount = layout.getChildCount();
if (childCount > 0) {
- i = numApps +
- (currentPage * numItemsPerPage) + (childCount / 2);
+ i = (currentPage * numItemsPerPage) + (childCount / 2);
}
} else {
throw new RuntimeException("Invalid ContentType");
@@ -314,13 +295,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int getPageForComponent(int index) {
if (index < 0) return 0;
- if (index < mApps.size()) {
- int numItemsPerPage = mCellCountX * mCellCountY;
- return (index / numItemsPerPage);
- } else {
- int numItemsPerPage = mWidgetCountX * mWidgetCountY;
- return (index - mApps.size()) / numItemsPerPage;
- }
+ int numItemsPerPage = mWidgetCountX * mWidgetCountY;
+ return index / numItemsPerPage;
}
/** Restores the page for an item at the specified index */
@@ -332,16 +308,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
private void updatePageCounts() {
mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
(float) (mWidgetCountX * mWidgetCountY));
- mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
}
protected void onDataReady(int width, int height) {
- // Now that the data is ready, we can calculate the content width, the number of cells to
- // use for each page
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- mCellCountX = (int) grid.allAppsNumCols;
- mCellCountY = (int) grid.allAppsNumRows;
updatePageCounts();
// Force a measure to update recalculate the gaps
@@ -360,7 +329,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
super.onLayout(changed, l, t, r, b);
if (!isDataReady()) {
- if ((!mApps.isEmpty()) && !mWidgets.isEmpty()) {
+ if (!mWidgets.isEmpty()) {
post(new Runnable() {
// This code triggers requestLayout so must be posted outside of the
// layout pass.
@@ -438,7 +407,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
@Override
public void onClick(View v) {
// When we have exited all apps or are in transition, disregard clicks
- if (!mLauncher.isAllAppsVisible()
+ if (!mLauncher.isWidgetsViewVisible()
|| mLauncher.getWorkspace().isSwitchingState()
|| !(v instanceof PagedViewWidget)) return;
@@ -456,11 +425,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
*/
@Override
protected void determineDraggingStart(android.view.MotionEvent ev) {
- // Disable dragging by pulling an app down for now.
- }
-
- private void beginDraggingApplication(View v) {
- mLauncher.getWorkspace().beginDragShared(v, this);
}
static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
@@ -681,12 +645,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
protected boolean beginDragging(final View v) {
if (!super.beginDragging(v)) return false;
- if (v instanceof BubbleTextView) {
- beginDraggingApplication(v);
- } else if (v instanceof PagedViewWidget) {
+ if (v instanceof PagedViewWidget) {
if (!beginDraggingWidget(v)) {
return false;
}
+ } else {
+ Log.e(TAG, "Unexpected dragging view: " + v);
}
// We delay entering spring-loaded mode slightly to make sure the UI
@@ -852,7 +816,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
// Clean up all the async tasks
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
+ AppsCustomizeAsyncTask task = iter.next();
task.cancel(false);
iter.remove();
mDirtyPageContent.set(task.page, true);
@@ -886,7 +850,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
// Update the thread priorities given the direction lookahead
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
+ AppsCustomizeAsyncTask task = iter.next();
int pageIndex = task.page;
if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) ||
(mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) {
@@ -897,36 +861,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
}
- /*
- * Apps PagedView implementation
- */
- private void setVisibilityOnChildren(ViewGroup layout, int visibility) {
- int childCount = layout.getChildCount();
- for (int i = 0; i < childCount; ++i) {
- layout.getChildAt(i).setVisibility(visibility);
- }
- }
- private void setupPage(AppsCustomizeCellLayout layout) {
- layout.setGridSize(mCellCountX, mCellCountY);
-
- // Note: We force a measure here to get around the fact that when we do layout calculations
- // immediately after syncing, we don't have a proper width. That said, we already know the
- // expected page width, so we can actually optimize by hiding all the TextView-based
- // children that are expensive to measure, and let that happen naturally later.
- setVisibilityOnChildren(layout, View.GONE);
- int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
- int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
- layout.measure(widthSpec, heightSpec);
-
- Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel);
- if (bg != null) {
- bg.setAlpha(mPageBackgroundsVisible ? 255: 0);
- layout.setBackground(bg);
- }
-
- setVisibilityOnChildren(layout, View.VISIBLE);
- }
-
public void setPageBackgroundsVisible(boolean visible) {
mPageBackgroundsVisible = visible;
int childCount = getChildCount();
@@ -938,43 +872,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
}
- public void syncAppsPageItems(int page, boolean immediate) {
- // ensure that we have the right number of items on the pages
- final boolean isRtl = isLayoutRtl();
- int numCells = mCellCountX * mCellCountY;
- int startIndex = page * numCells;
- int endIndex = Math.min(startIndex + numCells, mApps.size());
- AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(page);
-
- layout.removeAllViewsOnPage();
- ArrayList<Object> items = new ArrayList<Object>();
- ArrayList<Bitmap> images = new ArrayList<Bitmap>();
- for (int i = startIndex; i < endIndex; ++i) {
- AppInfo info = mApps.get(i);
- BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
- R.layout.apps_customize_application, layout, false);
- icon.applyFromApplicationInfo(info);
- icon.setOnClickListener(mLauncher);
- icon.setOnLongClickListener(this);
- icon.setOnTouchListener(this);
- icon.setOnKeyListener(mKeyListener);
- icon.setOnFocusChangeListener(layout.mFocusHandlerView);
-
- int index = i - startIndex;
- int x = index % mCellCountX;
- int y = index / mCellCountX;
- if (isRtl) {
- x = mCellCountX - x - 1;
- }
- layout.addViewToCellLayout(icon, -1, i, new CellLayout.LayoutParams(x,y, 1,1), false);
-
- items.add(info);
- images.add(info.iconBitmap);
- }
-
- enableHwLayersOnVisiblePages();
- }
-
/**
* A helper to return the priority for loading of the specified widget page.
*/
@@ -991,7 +888,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
int minPageDiff = Integer.MAX_VALUE;
while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
+ AppsCustomizeAsyncTask task = iter.next();
minPageDiff = Math.abs(task.page - toPage);
}
@@ -1026,7 +923,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
// Prune all tasks that are no longer needed
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
while (iter.hasNext()) {
- AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
+ AppsCustomizeAsyncTask task = iter.next();
int taskPage = task.page;
if (taskPage < getAssociatedLowerPageBound(mCurrentPage) ||
taskPage > getAssociatedUpperPageBound(mCurrentPage)) {
@@ -1264,14 +1161,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
cancelAllTasks();
Context context = getContext();
- if (mContentType == ContentType.Applications) {
- for (int i = 0; i < mNumAppsPages; ++i) {
- AppsCustomizeCellLayout layout = new AppsCustomizeCellLayout(context);
- setupPage(layout);
- addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.MATCH_PARENT));
- }
- } else if (mContentType == ContentType.Widgets) {
+ if (mContentType == ContentType.Widgets) {
for (int j = 0; j < mNumWidgetPages; ++j) {
PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
mWidgetCountY);
@@ -1291,7 +1181,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
if (mContentType == ContentType.Widgets) {
syncWidgetPageItems(page, immediate);
} else {
- syncAppsPageItems(page, immediate);
+ Log.e(TAG, "Unexpected ContentType");
}
}
@@ -1383,7 +1273,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
/**
- * We should call thise method whenever the core data changes (mApps, mWidgets) so that we can
+ * We should call thise method whenever the core data changes (mWidgets) so that we can
* appropriately determine when to invalidate the PagedView page data. In cases where the data
* has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
* next onMeasure() pass, which will trigger an invalidatePageData() itself.
@@ -1399,73 +1289,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
}
}
- public void setApps(ArrayList<AppInfo> list) {
- mApps = list;
- Collections.sort(mApps, LauncherModel.getAppNameComparator());
- updatePageCountsAndInvalidateData();
- }
-
- public ArrayList<AppInfo> getApps() {
- return mApps;
- }
-
- private void addAppsWithoutInvalidate(ArrayList<AppInfo> list) {
- // We add it in place, in alphabetical order
- int count = list.size();
- for (int i = 0; i < count; ++i) {
- AppInfo info = list.get(i);
- int index = Collections.binarySearch(mApps, info, LauncherModel.getAppNameComparator());
- if (index < 0) {
- mApps.add(-(index + 1), info);
- }
- }
- }
- public void addApps(ArrayList<AppInfo> list) {
- addAppsWithoutInvalidate(list);
- updatePageCountsAndInvalidateData();
- }
- private int findAppByComponent(List<AppInfo> list, AppInfo item) {
- ComponentName removeComponent = item.intent.getComponent();
- int length = list.size();
- for (int i = 0; i < length; ++i) {
- AppInfo info = list.get(i);
- if (info.user.equals(item.user)
- && info.intent.getComponent().equals(removeComponent)) {
- return i;
- }
- }
- return -1;
- }
- private void removeAppsWithoutInvalidate(ArrayList<AppInfo> list) {
- // loop through all the apps and remove apps that have the same component
- int length = list.size();
- for (int i = 0; i < length; ++i) {
- AppInfo info = list.get(i);
- int removeIndex = findAppByComponent(mApps, info);
- if (removeIndex > -1) {
- mApps.remove(removeIndex);
- }
- }
- }
- public void removeApps(ArrayList<AppInfo> appInfos) {
- removeAppsWithoutInvalidate(appInfos);
- updatePageCountsAndInvalidateData();
- }
- public void updateApps(ArrayList<AppInfo> list) {
- // We remove and re-add the updated applications list because it's properties may have
- // changed (ie. the title), and this will ensure that the items will be in their proper
- // place in the list.
- removeAppsWithoutInvalidate(list);
- addAppsWithoutInvalidate(list);
- updatePageCountsAndInvalidateData();
- }
-
public void reset() {
// If we have reset, then we should not continue to restore the previous state
mSaveInstanceStateItemIndex = -1;
- if (mContentType != ContentType.Applications) {
- setContentType(ContentType.Applications);
+ if (mContentType != ContentType.Widgets) {
+ setContentType(ContentType.Widgets);
}
if (mCurrentPage != 0) {
@@ -1479,7 +1308,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
public void dumpState() {
// TODO: Dump information related to current list of Applications, Widgets, etc.
- AppInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
}
@@ -1534,10 +1362,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int stringId = R.string.default_scroll_format;
int count = 0;
- if (mContentType == ContentType.Applications) {
- stringId = R.string.apps_customize_apps_scroll_format;
- count = mNumAppsPages;
- } else if (mContentType == ContentType.Widgets) {
+ if (mContentType == ContentType.Widgets) {
stringId = R.string.apps_customize_widgets_scroll_format;
count = mNumWidgetPages;
} else {
diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java
index a2717126d..5e2f05c61 100644
--- a/src/com/android/launcher3/AppsCustomizeTabHost.java
+++ b/src/com/android/launcher3/AppsCustomizeTabHost.java
@@ -27,7 +27,6 @@ import android.widget.FrameLayout;
public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable {
static final String LOG_TAG = "AppsCustomizeTabHost";
- private static final String APPS_TAB_TAG = "APPS";
private static final String WIDGETS_TAB_TAG = "WIDGETS";
private AppsCustomizePagedView mPagedView;
@@ -50,10 +49,6 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
mPagedView.setContentType(type);
}
- public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
- setContentTypeImmediate(type);
- }
-
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
@@ -79,27 +74,38 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
}
/**
+ * 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) {
- if (tag.equals(APPS_TAB_TAG)) {
- return AppsCustomizePagedView.ContentType.Applications;
- } else if (tag.equals(WIDGETS_TAB_TAG)) {
- return AppsCustomizePagedView.ContentType.Widgets;
- }
- return AppsCustomizePagedView.ContentType.Applications;
+ return AppsCustomizePagedView.ContentType.Widgets;
}
/**
* Returns the tab tag for a given content type.
*/
public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
- if (type == AppsCustomizePagedView.ContentType.Applications) {
- return APPS_TAB_TAG;
- } else if (type == AppsCustomizePagedView.ContentType.Widgets) {
- return WIDGETS_TAB_TAG;
- }
- return APPS_TAB_TAG;
+ return WIDGETS_TAB_TAG;
}
/**
@@ -199,6 +205,7 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
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()) {
@@ -207,7 +214,8 @@ public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransit
if (child == this) {
break;
} else {
- if (child.getVisibility() == GONE || child == overviewPanel) {
+ if (child.getVisibility() == GONE || child == overviewPanel ||
+ child == appsView) {
continue;
}
child.setVisibility(visibility);
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index f9255e6bd..5ea84aeb2 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -28,6 +28,7 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -49,7 +50,7 @@ public class BubbleTextView extends TextView {
private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
static final float PADDING_V = 3.0f;
-
+ private Drawable mIcon;
private final Drawable mBackground;
private final CheckLongPressHelper mLongPressHelper;
private final HolographicOutlineHelper mOutlineHelper;
@@ -62,9 +63,12 @@ public class BubbleTextView extends TextView {
private float mSlop;
- private int mTextColor;
private final boolean mCustomShadowsEnabled;
- private boolean mIsTextVisible;
+ private final boolean mLayoutHorizontal;
+ private final int mIconSize;
+ private final int mIconPaddingSize;
+ private final int mTextSize;
+ private int mTextColor;
private boolean mStayPressed;
private boolean mIgnorePressedStateChange;
@@ -79,10 +83,19 @@ public class BubbleTextView extends TextView {
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true);
+ mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
+ mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
+ grid.allAppsIconSizePx);
+ mIconPaddingSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconPaddingOverride,
+ grid.iconDrawablePaddingPx);
+ mTextSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_textSizeOverride,
+ grid.allAppsIconTextSizePx);
a.recycle();
if (mCustomShadowsEnabled) {
@@ -92,6 +105,12 @@ public class BubbleTextView extends TextView {
} else {
mBackground = null;
}
+
+ // If we are laying out horizontal, then center the text vertically
+ if (mLayoutHorizontal) {
+ setGravity(Gravity.CENTER_VERTICAL);
+ }
+
mLongPressHelper = new CheckLongPressHelper(this);
mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
@@ -106,9 +125,7 @@ public class BubbleTextView extends TextView {
super.onFinishInflate();
// Ensure we are using the right text size
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
}
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
@@ -119,16 +136,11 @@ public class BubbleTextView extends TextView {
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
boolean setDefaultPadding, boolean promiseStateChanged) {
Bitmap b = info.getIcon(iconCache);
- LauncherAppState app = LauncherAppState.getInstance();
FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
- setCompoundDrawables(null, iconDrawable, null, null);
- if (setDefaultPadding) {
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
- }
+ setIcon(iconDrawable, mIconSize, setDefaultPadding ? mIconPaddingSize : -1);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
}
@@ -141,13 +153,7 @@ public class BubbleTextView extends TextView {
}
public void applyFromApplicationInfo(AppInfo info) {
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
- Drawable topDrawable = Utilities.createIconDrawable(info.iconBitmap);
- topDrawable.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx);
- setCompoundDrawables(null, topDrawable, null, null);
- setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
+ setIcon(Utilities.createIconDrawable(info.iconBitmap), mIconSize, mIconPaddingSize);
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
@@ -155,7 +161,6 @@ public class BubbleTextView extends TextView {
setTag(info);
}
-
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
@@ -186,10 +191,19 @@ public class BubbleTextView extends TextView {
}
}
+ /** Returns the icon for this view. */
+ public Drawable getIcon() {
+ return mIcon;
+ }
+
+ /** Returns whether the layout is horizontal. */
+ public boolean isLayoutHorizontal() {
+ return mLayoutHorizontal;
+ }
+
private void updateIconState() {
- Drawable top = getCompoundDrawables()[1];
- if (top instanceof FastBitmapDrawable) {
- ((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed);
+ if (mIcon instanceof FastBitmapDrawable) {
+ ((FastBitmapDrawable) mIcon).setPressed(isPressed() || mStayPressed);
}
}
@@ -325,10 +339,9 @@ public class BubbleTextView extends TextView {
super.onAttachedToWindow();
if (mBackground != null) mBackground.setCallback(this);
- Drawable top = getCompoundDrawables()[1];
- if (top instanceof PreloadIconDrawable) {
- ((PreloadIconDrawable) top).applyPreloaderTheme(getPreloaderTheme());
+ if (mIcon instanceof PreloadIconDrawable) {
+ ((PreloadIconDrawable) mIcon).applyPreloaderTheme(getPreloaderTheme());
}
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
@@ -358,11 +371,6 @@ public class BubbleTextView extends TextView {
} else {
super.setTextColor(res.getColor(android.R.color.transparent));
}
- mIsTextVisible = visible;
- }
-
- public boolean isTextVisible() {
- return mIsTextVisible;
}
@Override
@@ -385,15 +393,13 @@ public class BubbleTextView extends TextView {
((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ?
info.getInstallProgress() : 0)) : 100;
- Drawable[] drawables = getCompoundDrawables();
- Drawable top = drawables[1];
- if (top != null) {
+ if (mIcon != null) {
final PreloadIconDrawable preloadDrawable;
- if (top instanceof PreloadIconDrawable) {
- preloadDrawable = (PreloadIconDrawable) top;
+ if (mIcon instanceof PreloadIconDrawable) {
+ preloadDrawable = (PreloadIconDrawable) mIcon;
} else {
- preloadDrawable = new PreloadIconDrawable(top, getPreloaderTheme());
- setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]);
+ preloadDrawable = new PreloadIconDrawable(mIcon, getPreloaderTheme());
+ setIcon(preloadDrawable, mIconSize, -1);
}
preloadDrawable.setLevel(progressLevel);
@@ -417,4 +423,23 @@ public class BubbleTextView extends TextView {
}
return theme;
}
+
+ /**
+ * Sets the icon for this view based on the layout direction.
+ */
+ private Drawable setIcon(Drawable icon, int iconSize, int drawablePadding) {
+ mIcon = icon;
+ if (iconSize != -1) {
+ mIcon.setBounds(0, 0, iconSize, iconSize);
+ }
+ if (mLayoutHorizontal) {
+ setCompoundDrawablesRelative(mIcon, null, null, null);
+ } else {
+ setCompoundDrawablesRelative(null, mIcon, null, null);
+ }
+ if (drawablePadding != -1) {
+ setCompoundDrawablePadding(drawablePadding);
+ }
+ return icon;
+ }
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 7d02e10b5..b5bb55ca7 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -122,6 +122,8 @@ public class DeviceProfile {
int hotseatAllAppsRank;
int allAppsNumRows;
int allAppsNumCols;
+ // TODO(winsonc): to be used with the grid layout
+ int allAppsRowsSize;
int searchBarSpaceWidthPx;
int searchBarSpaceHeightPx;
int pageIndicatorHeightPx;
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 0a6557907..f6b05208b 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -24,6 +24,7 @@ import android.animation.PropertyValuesHolder;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
@@ -46,7 +47,6 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.TextView;
-
import com.android.launcher3.FolderInfo.FolderListener;
import com.android.launcher3.Workspace.ItemOperator;
@@ -219,7 +219,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
return false;
}
- mLauncher.getWorkspace().beginDragShared(v, this);
+ mLauncher.getWorkspace().beginDragShared(v, new Point(), this, false);
mCurrentDragInfo = item;
mEmptyCellRank = item.rank;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 984d536a5..9c4632cc8 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2008 The Android Open Source Project
*
@@ -22,7 +21,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.Activity;
@@ -48,7 +46,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
@@ -82,15 +79,12 @@ import android.view.Surface;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
-import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.Advanceable;
import android.widget.FrameLayout;
@@ -132,7 +126,8 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public class Launcher extends Activity
implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
- View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener {
+ View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener,
+ LauncherStateTransitionAnimation.Callbacks {
static final String TAG = "Launcher";
static final boolean LOGD = false;
@@ -213,9 +208,10 @@ public class Launcher extends Activity
public static final String USER_HAS_MIGRATED = "launcher.user_migrated_from_old_data";
/** The different states that Launcher can be in. */
- private enum State { NONE, WORKSPACE, APPS_CUSTOMIZE, APPS_CUSTOMIZE_SPRING_LOADED };
+ enum State { NONE, WORKSPACE, APPS, APPS_SPRING_LOADED, WIDGETS, WIDGETS_SPRING_LOADED };
private State mState = State.WORKSPACE;
private AnimatorSet mStateAnimation;
+ private LauncherStateTransitionAnimation mStateTransitionAnimation;
private boolean mIsSafeModeEnabled;
@@ -235,7 +231,6 @@ public class Launcher extends Activity
private static int NEW_APPS_PAGE_MOVE_DELAY = 500;
private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
private static int NEW_APPS_ANIMATION_DELAY = 500;
- private static final int SINGLE_FRAME_DELAY = 16;
private final BroadcastReceiver mCloseSystemDialogsReceiver
= new CloseSystemDialogsIntentReceiver();
@@ -267,6 +262,7 @@ public class Launcher extends Activity
private View mAllAppsButton;
private SearchDropTargetBar mSearchDropTargetBar;
+ private AppsContainerView mAppsView;
private AppsCustomizeTabHost mAppsCustomizeTabHost;
private AppsCustomizePagedView mAppsCustomizeContent;
private boolean mAutoAdvanceRunning = false;
@@ -305,9 +301,6 @@ public class Launcher extends Activity
private View.OnTouchListener mHapticFeedbackTouchListener;
- public static final int BUILD_LAYER = 0;
- public static final int BUILD_AND_SET_LAYER = 1;
-
// Related to the auto-advancing of widgets
private final int ADVANCE_MSG = 1;
private final int mAdvanceInterval = 20000;
@@ -431,6 +424,7 @@ public class Launcher extends Activity
mIconCache.flushInvalidIcons(grid);
mDragController = new DragController(this);
mInflater = getLayoutInflater();
+ mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, this);
mStats = new Stats(this);
@@ -990,10 +984,12 @@ public class Launcher extends Activity
super.onResume();
// Restore the previous launcher state
- if (mOnResumeState == State.WORKSPACE) {
+ if (mOnResumeState == State.WORKSPACE || mOnResumeState == State.NONE) {
showWorkspace(false);
- } else if (mOnResumeState == State.APPS_CUSTOMIZE) {
- showAllApps(false, mAppsCustomizeContent.getContentType(), false);
+ } else if (mOnResumeState == State.APPS) {
+ showAppsView(false /* animated */, false /* resetListToTop */);
+ } else if (mOnResumeState == State.WIDGETS) {
+ showWidgetsView(false, false);
}
mOnResumeState = State.NONE;
@@ -1302,8 +1298,8 @@ public class Launcher extends Activity
}
State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
- if (state == State.APPS_CUSTOMIZE) {
- mOnResumeState = State.APPS_CUSTOMIZE;
+ if (state == State.APPS || state == State.WIDGETS) {
+ mOnResumeState = state;
}
int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN,
@@ -1429,6 +1425,9 @@ public class Launcher extends Activity
mSearchDropTargetBar = (SearchDropTargetBar)
mDragLayer.findViewById(R.id.search_drop_target_bar);
+ // Setup Apps
+ mAppsView = (AppsContainerView) findViewById(R.id.apps_view);
+
// Setup AppsCustomize
mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane);
mAppsCustomizeContent = (AppsCustomizePagedView)
@@ -1646,16 +1645,17 @@ public class Launcher extends Activity
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
mUserPresent = false;
mDragLayer.clearAllResizeFrames();
- updateRunning();
+ updateAutoAdvanceState();
// Reset AllApps to its initial state only if we are not in the middle of
// processing a multi-step drop
- if (mAppsCustomizeTabHost != null && mPendingAddInfo.container == ItemInfo.NO_ID) {
+ if (mAppsView != null && mAppsCustomizeTabHost != null &&
+ mPendingAddInfo.container == ItemInfo.NO_ID) {
showWorkspace(false);
}
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
mUserPresent = true;
- updateRunning();
+ updateAutoAdvanceState();
} else if (ENABLE_DEBUG_INTENTS && DebugIntents.DELETE_DATABASE.equals(action)) {
mModel.resetLoadedState(false, true);
mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
@@ -1723,12 +1723,12 @@ public class Launcher extends Activity
unregisterReceiver(mReceiver);
mAttached = false;
}
- updateRunning();
+ updateAutoAdvanceState();
}
public void onWindowVisibilityChanged(int visibility) {
mVisible = visibility == View.VISIBLE;
- updateRunning();
+ updateAutoAdvanceState();
// The following code used to be in onResume, but it turns out onResume is called when
// you're in All Apps and click home to go to the workspace. onWindowVisibilityChanged
// is a more appropriate event to handle
@@ -1775,7 +1775,7 @@ public class Launcher extends Activity
mAutoAdvanceSentTime = System.currentTimeMillis();
}
- private void updateRunning() {
+ private void updateAutoAdvanceState() {
boolean autoAdvanceRunning = mVisible && mUserPresent && !mWidgetsToAdvance.isEmpty();
if (autoAdvanceRunning != mAutoAdvanceRunning) {
mAutoAdvanceRunning = autoAdvanceRunning;
@@ -1821,14 +1821,14 @@ public class Launcher extends Activity
if (v instanceof Advanceable) {
mWidgetsToAdvance.put(hostView, appWidgetInfo);
((Advanceable) v).fyiWillBeAdvancedByHostKThx();
- updateRunning();
+ updateAutoAdvanceState();
}
}
void removeWidgetToAutoAdvance(View hostView) {
if (mWidgetsToAdvance.containsKey(hostView)) {
mWidgetsToAdvance.remove(hostView);
- updateRunning();
+ updateAutoAdvanceState();
}
}
@@ -1842,14 +1842,18 @@ public class Launcher extends Activity
Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show();
}
- public ArrayList<AppInfo> getAllAppsList() {
- return mAppsCustomizeContent.getApps();
- }
-
public DragLayer getDragLayer() {
return mDragLayer;
}
+ public AppsContainerView getAppsView() {
+ return mAppsView;
+ }
+
+ public AppsCustomizeTabHost getWidgetsView() {
+ return mAppsCustomizeTabHost;
+ }
+
public Workspace getWorkspace() {
return mWorkspace;
}
@@ -1935,6 +1939,11 @@ public class Launcher extends Activity
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
+ // Reset the apps view
+ if (!alreadyOnHome && mAppsView != null) {
+ mAppsView.scrollToTop();
+ }
+
// Reset the apps customize page
if (!alreadyOnHome && mAppsCustomizeTabHost != null) {
mAppsCustomizeTabHost.reset();
@@ -2452,13 +2461,10 @@ public class Launcher extends Activity
return;
}
- if (isAllAppsVisible()) {
- if (mAppsCustomizeContent.getContentType() ==
- AppsCustomizePagedView.ContentType.Applications) {
- showWorkspace(true);
- } else {
- showOverviewMode(true);
- }
+ if (isAppsViewVisible()) {
+ showWorkspace(true);
+ } else if (isWidgetsViewVisible()) {
+ showOverviewMode(true);
} else if (mWorkspace.isInOverviewMode()) {
mWorkspace.exitOverviewMode(true);
} else if (mWorkspace.getOpenFolder() != null) {
@@ -2589,10 +2595,10 @@ public class Launcher extends Activity
*/
protected void onClickAllAppsButton(View v) {
if (LOGD) Log.d(TAG, "onClickAllAppsButton");
- if (isAllAppsVisible()) {
+ if (isAppsViewVisible()) {
showWorkspace(true);
} else {
- showAllApps(true, AppsCustomizePagedView.ContentType.Applications, false);
+ showAppsView(true /* animated */, false /* resetListToTop */);
}
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onClickAllAppsButton(v);
@@ -2763,7 +2769,7 @@ public class Launcher extends Activity
if (mIsSafeModeEnabled) {
Toast.makeText(this, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
} else {
- showAllApps(true, AppsCustomizePagedView.ContentType.Widgets, true);
+ showWidgetsView(true /* animated */, true /* resetPageToZero */);
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onClickAddWidgetButton(view);
}
@@ -2920,12 +2926,11 @@ public class Launcher extends Activity
int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
if (v instanceof TextView) {
// Launch from center of icon, not entire view
- TextView tv = (TextView) v;
- Drawable[] drawables = tv.getCompoundDrawables();
- if (drawables != null && drawables[1] != null) {
- Rect bounds = drawables[1].getBounds();
+ Drawable icon = Workspace.getTextViewIcon((TextView) v);
+ if (icon != null) {
+ Rect bounds = icon.getBounds();
left = (width - bounds.width()) / 2;
- top = tv.getPaddingTop();
+ top = v.getPaddingTop();
width = bounds.width();
height = bounds.height();
}
@@ -3219,12 +3224,23 @@ public class Launcher extends Activity
return null;
}
} else {
- return (CellLayout) mWorkspace.getScreenWithId(screenId);
+ return mWorkspace.getScreenWithId(screenId);
}
}
+ /**
+ * For overridden classes.
+ */
public boolean isAllAppsVisible() {
- return (mState == State.APPS_CUSTOMIZE) || (mOnResumeState == State.APPS_CUSTOMIZE);
+ return isAppsViewVisible();
+ }
+
+ public boolean isAppsViewVisible() {
+ return (mState == State.APPS) || (mOnResumeState == State.APPS);
+ }
+
+ public boolean isWidgetsViewVisible() {
+ return (mState == State.WIDGETS) || (mOnResumeState == State.WIDGETS);
}
private void setWorkspaceBackground(boolean workspace) {
@@ -3242,578 +3258,6 @@ public class Launcher extends Activity
setWorkspaceBackground(visible);
}
- private void dispatchOnLauncherTransitionPrepare(View v, boolean animated, boolean toWorkspace) {
- if (v instanceof LauncherTransitionable) {
- ((LauncherTransitionable) v).onLauncherTransitionPrepare(this, animated, toWorkspace);
- }
- }
-
- private void dispatchOnLauncherTransitionStart(View v, boolean animated, boolean toWorkspace) {
- if (v instanceof LauncherTransitionable) {
- ((LauncherTransitionable) v).onLauncherTransitionStart(this, animated, toWorkspace);
- }
-
- // Update the workspace transition step as well
- dispatchOnLauncherTransitionStep(v, 0f);
- }
-
- private void dispatchOnLauncherTransitionStep(View v, float t) {
- if (v instanceof LauncherTransitionable) {
- ((LauncherTransitionable) v).onLauncherTransitionStep(this, t);
- }
- }
-
- private void dispatchOnLauncherTransitionEnd(View v, boolean animated, boolean toWorkspace) {
- if (v instanceof LauncherTransitionable) {
- ((LauncherTransitionable) v).onLauncherTransitionEnd(this, animated, toWorkspace);
- }
-
- // Update the workspace transition step as well
- dispatchOnLauncherTransitionStep(v, 1f);
- }
-
- /**
- * Things to test when changing the following seven functions.
- * - Home from workspace
- * - from center screen
- * - from other screens
- * - Home from all apps
- * - from center screen
- * - from other screens
- * - Back from all apps
- * - from center screen
- * - from other screens
- * - Launch app from workspace and quit
- * - with back
- * - with home
- * - Launch app from all apps and quit
- * - with back
- * - with home
- * - Go to a screen that's not the default, then all
- * apps, and launch and app, and go back
- * - with back
- * -with home
- * - On workspace, long press power and go back
- * - with back
- * - with home
- * - On all apps, long press power and go back
- * - with back
- * - with home
- * - On workspace, power off
- * - On all apps, power off
- * - Launch an app and turn off the screen while in that app
- * - Go back with home key
- * - Go back with back key TODO: make this not go to workspace
- * - From all apps
- * - From workspace
- * - Enter and exit car mode (becuase it causes an extra configuration changed)
- * - From all apps
- * - From the center workspace
- * - From another workspace
- */
-
- /**
- * Zoom the camera out from the workspace to reveal 'toView'.
- * Assumes that the view to show is anchored at either the very top or very bottom
- * of the screen.
- */
- private void showAppsCustomizeHelper(final boolean animated, final boolean springLoaded) {
- AppsCustomizePagedView.ContentType contentType = mAppsCustomizeContent.getContentType();
- showAppsCustomizeHelper(animated, springLoaded, contentType);
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- private void showAppsCustomizeHelper(final boolean animated, final boolean springLoaded,
- final AppsCustomizePagedView.ContentType contentType) {
- if (mStateAnimation != null) {
- mStateAnimation.setDuration(0);
- mStateAnimation.cancel();
- mStateAnimation = null;
- }
-
- boolean material = Utilities.isLmpOrAbove();
-
- final Resources res = getResources();
-
- final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
- final int itemsAlphaStagger =
- res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
-
- final View fromView = mWorkspace;
- final AppsCustomizeTabHost toView = mAppsCustomizeTabHost;
-
- final HashMap<View, Integer> layerViews = new HashMap<View, Integer>();
-
- Workspace.State workspaceState = contentType == AppsCustomizePagedView.ContentType.Widgets ?
- Workspace.State.OVERVIEW_HIDDEN : Workspace.State.NORMAL_HIDDEN;
- Animator workspaceAnim =
- mWorkspace.getChangeStateAnimation(workspaceState, animated, layerViews);
- if (contentType == AppsCustomizePagedView.ContentType.Widgets) {
- // Set the content type for the all apps/widgets space
- mAppsCustomizeTabHost.setContentTypeImmediate(contentType);
- }
-
- // If for some reason our views aren't initialized, don't animate
- boolean initialized = getAllAppsButton() != null;
-
- if (animated && initialized) {
- mStateAnimation = LauncherAnimUtils.createAnimatorSet();
- final AppsCustomizePagedView content = (AppsCustomizePagedView)
- toView.findViewById(R.id.apps_customize_pane_content);
-
- final View page = content.getPageAt(content.getCurrentPage());
- final View revealView = toView.findViewById(R.id.fake_page);
-
- final boolean isWidgetTray = contentType == AppsCustomizePagedView.ContentType.Widgets;
- if (isWidgetTray) {
- revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark));
- } else {
- revealView.setBackground(res.getDrawable(R.drawable.quantum_panel));
- }
-
- // Hide the real page background, and swap in the fake one
- content.setPageBackgroundsVisible(false);
- revealView.setVisibility(View.VISIBLE);
- // We need to hide this view as the animation start will be posted.
- revealView.setAlpha(0);
-
- int width = revealView.getMeasuredWidth();
- int height = revealView.getMeasuredHeight();
- float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
-
- revealView.setTranslationY(0);
- revealView.setTranslationX(0);
-
- // Get the y delta between the center of the page and the center of the all apps button
- int[] allAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
- getAllAppsButton(), null);
-
- float alpha = 0;
- float xDrift = 0;
- float yDrift = 0;
- if (material) {
- alpha = isWidgetTray ? 0.3f : 1f;
- yDrift = isWidgetTray ? height / 2 : allAppsToPanelDelta[1];
- xDrift = isWidgetTray ? 0 : allAppsToPanelDelta[0];
- } else {
- yDrift = 2 * height / 3;
- xDrift = 0;
- }
- final float initAlpha = alpha;
-
- layerViews.put(revealView, BUILD_AND_SET_LAYER);
- PropertyValuesHolder panelAlpha = PropertyValuesHolder.ofFloat("alpha", initAlpha, 1f);
- PropertyValuesHolder panelDriftY =
- PropertyValuesHolder.ofFloat("translationY", yDrift, 0);
- PropertyValuesHolder panelDriftX =
- PropertyValuesHolder.ofFloat("translationX", xDrift, 0);
-
- ObjectAnimator panelAlphaAndDrift = ObjectAnimator.ofPropertyValuesHolder(revealView,
- panelAlpha, panelDriftY, panelDriftX);
-
- panelAlphaAndDrift.setDuration(revealDuration);
- panelAlphaAndDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
-
- mStateAnimation.play(panelAlphaAndDrift);
-
- if (page != null) {
- page.setVisibility(View.VISIBLE);
- layerViews.put(page, BUILD_AND_SET_LAYER);
-
- ObjectAnimator pageDrift = ObjectAnimator.ofFloat(page, "translationY", yDrift, 0);
- page.setTranslationY(yDrift);
- pageDrift.setDuration(revealDuration);
- pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
- pageDrift.setStartDelay(itemsAlphaStagger);
- mStateAnimation.play(pageDrift);
-
- page.setAlpha(0f);
- ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(page, "alpha", 0f, 1f);
- itemsAlpha.setDuration(revealDuration);
- itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
- itemsAlpha.setStartDelay(itemsAlphaStagger);
- mStateAnimation.play(itemsAlpha);
- }
-
- View pageIndicators = toView.findViewById(R.id.apps_customize_page_indicator);
- pageIndicators.setAlpha(0.01f);
- ObjectAnimator indicatorsAlpha =
- ObjectAnimator.ofFloat(pageIndicators, "alpha", 1f);
- indicatorsAlpha.setDuration(revealDuration);
- mStateAnimation.play(indicatorsAlpha);
-
- if (material) {
- final View allApps = getAllAppsButton();
- int allAppsButtonSize = LauncherAppState.getInstance().
- getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
- float startRadius = isWidgetTray ? 0 : allAppsButtonSize / 2;
- Animator reveal = ViewAnimationUtils.createCircularReveal(revealView, width / 2,
- height / 2, startRadius, revealRadius);
- reveal.setDuration(revealDuration);
- reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
-
- reveal.addListener(new AnimatorListenerAdapter() {
- public void onAnimationStart(Animator animation) {
- if (!isWidgetTray) {
- allApps.setVisibility(View.INVISIBLE);
- }
- }
- public void onAnimationEnd(Animator animation) {
- if (!isWidgetTray) {
- allApps.setVisibility(View.VISIBLE);
- }
- }
- });
- mStateAnimation.play(reveal);
- }
-
- mStateAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- dispatchOnLauncherTransitionEnd(fromView, animated, false);
- dispatchOnLauncherTransitionEnd(toView, animated, false);
-
- revealView.setVisibility(View.INVISIBLE);
-
- for (View v : layerViews.keySet()) {
- if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
- v.setLayerType(View.LAYER_TYPE_NONE, null);
- }
- }
- content.setPageBackgroundsVisible(true);
-
- // Hide the search bar
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.hideSearchBar(false);
- }
-
- // This can hold unnecessary references to views.
- mStateAnimation = null;
- }
-
- });
-
- if (workspaceAnim != null) {
- mStateAnimation.play(workspaceAnim);
- }
-
- dispatchOnLauncherTransitionPrepare(fromView, animated, false);
- dispatchOnLauncherTransitionPrepare(toView, animated, false);
- final AnimatorSet stateAnimation = mStateAnimation;
- final Runnable startAnimRunnable = new Runnable() {
- public void run() {
- // Check that mStateAnimation hasn't changed while
- // we waited for a layout/draw pass
- if (mStateAnimation != stateAnimation)
- return;
- dispatchOnLauncherTransitionStart(fromView, animated, false);
- dispatchOnLauncherTransitionStart(toView, animated, false);
-
- revealView.setAlpha(initAlpha);
-
- for (View v : layerViews.keySet()) {
- if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
- v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- }
- }
-
- if (Utilities.isLmpOrAbove()) {
- for (View v : layerViews.keySet()) {
- if (Utilities.isViewAttachedToWindow(v)) v.buildLayer();
- }
- }
- mStateAnimation.start();
- }
- };
- toView.bringToFront();
- toView.setVisibility(View.VISIBLE);
- toView.post(startAnimRunnable);
- } else {
- toView.setTranslationX(0.0f);
- toView.setTranslationY(0.0f);
- toView.setScaleX(1.0f);
- toView.setScaleY(1.0f);
- toView.setVisibility(View.VISIBLE);
- toView.bringToFront();
-
- if (!springLoaded && !LauncherAppState.getInstance().isScreenLarge()) {
- // Hide the search bar
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.hideSearchBar(false);
- }
- }
- dispatchOnLauncherTransitionPrepare(fromView, animated, false);
- dispatchOnLauncherTransitionStart(fromView, animated, false);
- dispatchOnLauncherTransitionEnd(fromView, animated, false);
- dispatchOnLauncherTransitionPrepare(toView, animated, false);
- dispatchOnLauncherTransitionStart(toView, animated, false);
- dispatchOnLauncherTransitionEnd(toView, animated, false);
- }
- }
-
- /**
- * Zoom the camera back into the workspace, hiding 'fromView'.
- * This is the opposite of showAppsCustomizeHelper.
- * @param animated If true, the transition will be animated.
- */
- private void hideAppsCustomizeHelper(Workspace.State toState, final boolean animated,
- final boolean springLoaded, final Runnable onCompleteRunnable) {
-
- if (mStateAnimation != null) {
- mStateAnimation.setDuration(0);
- mStateAnimation.cancel();
- mStateAnimation = null;
- }
-
- boolean material = Utilities.isLmpOrAbove();
- Resources res = getResources();
-
- final int revealDuration = res.getInteger(R.integer.config_appsCustomizeConcealTime);
- final int itemsAlphaStagger =
- res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
-
- final View fromView = mAppsCustomizeTabHost;
- final View toView = mWorkspace;
- Animator workspaceAnim = null;
- final HashMap<View, Integer> layerViews = new HashMap<View, Integer>();
-
- if (toState == Workspace.State.NORMAL) {
- workspaceAnim = mWorkspace.getChangeStateAnimation(
- toState, animated, layerViews);
- } else if (toState == Workspace.State.SPRING_LOADED ||
- toState == Workspace.State.OVERVIEW) {
- workspaceAnim = mWorkspace.getChangeStateAnimation(
- toState, animated, layerViews);
- }
-
- // If for some reason our views aren't initialized, don't animate
- boolean initialized = getAllAppsButton() != null;
-
- if (animated && initialized) {
- mStateAnimation = LauncherAnimUtils.createAnimatorSet();
- if (workspaceAnim != null) {
- mStateAnimation.play(workspaceAnim);
- }
-
- final AppsCustomizePagedView content = (AppsCustomizePagedView)
- fromView.findViewById(R.id.apps_customize_pane_content);
-
- final View page = content.getPageAt(content.getNextPage());
-
- // We need to hide side pages of the Apps / Widget tray to avoid some ugly edge cases
- int count = content.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = content.getChildAt(i);
- if (child != page) {
- child.setVisibility(View.INVISIBLE);
- }
- }
- final View revealView = fromView.findViewById(R.id.fake_page);
-
- // hideAppsCustomizeHelper is called in some cases when it is already hidden
- // don't perform all these no-op animations. In particularly, this was causing
- // the all-apps button to pop in and out.
- if (fromView.getVisibility() == View.VISIBLE) {
- AppsCustomizePagedView.ContentType contentType = content.getContentType();
- final boolean isWidgetTray =
- contentType == AppsCustomizePagedView.ContentType.Widgets;
-
- if (isWidgetTray) {
- revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark));
- } else {
- revealView.setBackground(res.getDrawable(R.drawable.quantum_panel));
- }
-
- int width = revealView.getMeasuredWidth();
- int height = revealView.getMeasuredHeight();
- float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
-
- // Hide the real page background, and swap in the fake one
- revealView.setVisibility(View.VISIBLE);
- content.setPageBackgroundsVisible(false);
-
- final View allAppsButton = getAllAppsButton();
- revealView.setTranslationY(0);
- int[] allAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
- allAppsButton, null);
-
- float xDrift = 0;
- float yDrift = 0;
- if (material) {
- yDrift = isWidgetTray ? height / 2 : allAppsToPanelDelta[1];
- xDrift = isWidgetTray ? 0 : allAppsToPanelDelta[0];
- } else {
- yDrift = 2 * height / 3;
- xDrift = 0;
- }
-
- layerViews.put(revealView, BUILD_AND_SET_LAYER);
- TimeInterpolator decelerateInterpolator = material ?
- new LogDecelerateInterpolator(100, 0) :
- new DecelerateInterpolator(1f);
-
- // The vertical motion of the apps panel should be delayed by one frame
- // from the conceal animation in order to give the right feel. We correpsondingly
- // shorten the duration so that the slide and conceal end at the same time.
- ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY",
- 0, yDrift);
- panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
- panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
- panelDriftY.setInterpolator(decelerateInterpolator);
- mStateAnimation.play(panelDriftY);
-
- ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX",
- 0, xDrift);
- panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
- panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
- panelDriftX.setInterpolator(decelerateInterpolator);
- mStateAnimation.play(panelDriftX);
-
- if (isWidgetTray || !material) {
- float finalAlpha = material ? 0.4f : 0f;
- revealView.setAlpha(1f);
- ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha",
- 1f, finalAlpha);
- panelAlpha.setDuration(material ? revealDuration : 150);
- panelAlpha.setInterpolator(decelerateInterpolator);
- panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
- mStateAnimation.play(panelAlpha);
- }
-
- if (page != null) {
- layerViews.put(page, BUILD_AND_SET_LAYER);
-
- ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(page, "translationY",
- 0, yDrift);
- page.setTranslationY(0);
- pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
- pageDrift.setInterpolator(decelerateInterpolator);
- pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
- mStateAnimation.play(pageDrift);
-
- page.setAlpha(1f);
- ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(page, "alpha", 1f, 0f);
- itemsAlpha.setDuration(100);
- itemsAlpha.setInterpolator(decelerateInterpolator);
- mStateAnimation.play(itemsAlpha);
- }
-
- View pageIndicators = fromView.findViewById(R.id.apps_customize_page_indicator);
- pageIndicators.setAlpha(1f);
- ObjectAnimator indicatorsAlpha =
- LauncherAnimUtils.ofFloat(pageIndicators, "alpha", 0f);
- indicatorsAlpha.setDuration(revealDuration);
- indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
- mStateAnimation.play(indicatorsAlpha);
-
- width = revealView.getMeasuredWidth();
-
- if (material) {
- if (!isWidgetTray) {
- allAppsButton.setVisibility(View.INVISIBLE);
- }
- int allAppsButtonSize = LauncherAppState.getInstance().
- getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
- float finalRadius = isWidgetTray ? 0 : allAppsButtonSize / 2;
- Animator reveal =
- LauncherAnimUtils.createCircularReveal(revealView, width / 2,
- height / 2, revealRadius, finalRadius);
- reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
- reveal.setDuration(revealDuration);
- reveal.setStartDelay(itemsAlphaStagger);
-
- reveal.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- revealView.setVisibility(View.INVISIBLE);
- if (!isWidgetTray) {
- allAppsButton.setVisibility(View.VISIBLE);
- }
- }
- });
-
- mStateAnimation.play(reveal);
- }
-
- dispatchOnLauncherTransitionPrepare(fromView, animated, true);
- dispatchOnLauncherTransitionPrepare(toView, animated, true);
- mAppsCustomizeContent.stopScrolling();
- }
-
- mStateAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- fromView.setVisibility(View.GONE);
- dispatchOnLauncherTransitionEnd(fromView, animated, true);
- dispatchOnLauncherTransitionEnd(toView, animated, true);
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
-
- for (View v : layerViews.keySet()) {
- if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
- v.setLayerType(View.LAYER_TYPE_NONE, null);
- }
- }
-
- content.setPageBackgroundsVisible(true);
- // Unhide side pages
- int count = content.getChildCount();
- for (int i = 0; i < count; i++) {
- View child = content.getChildAt(i);
- child.setVisibility(View.VISIBLE);
- }
-
- // Reset page transforms
- if (page != null) {
- page.setTranslationX(0);
- page.setTranslationY(0);
- page.setAlpha(1);
- }
- content.setCurrentPage(content.getNextPage());
-
- mAppsCustomizeContent.updateCurrentPageScroll();
-
- // This can hold unnecessary references to views.
- mStateAnimation = null;
- }
- });
-
- final AnimatorSet stateAnimation = mStateAnimation;
- final Runnable startAnimRunnable = new Runnable() {
- public void run() {
- // Check that mStateAnimation hasn't changed while
- // we waited for a layout/draw pass
- if (mStateAnimation != stateAnimation)
- return;
- dispatchOnLauncherTransitionStart(fromView, animated, false);
- dispatchOnLauncherTransitionStart(toView, animated, false);
-
- for (View v : layerViews.keySet()) {
- if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
- v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- }
- }
-
- if (Utilities.isLmpOrAbove()) {
- for (View v : layerViews.keySet()) {
- if (Utilities.isViewAttachedToWindow(v)) v.buildLayer();
- }
- }
- mStateAnimation.start();
- }
- };
- fromView.post(startAnimRunnable);
- } else {
- fromView.setVisibility(View.GONE);
- dispatchOnLauncherTransitionPrepare(fromView, animated, true);
- dispatchOnLauncherTransitionStart(fromView, animated, true);
- dispatchOnLauncherTransitionEnd(fromView, animated, true);
- dispatchOnLauncherTransitionPrepare(toView, animated, true);
- dispatchOnLauncherTransitionStart(toView, animated, true);
- dispatchOnLauncherTransitionEnd(toView, animated, true);
- }
- }
-
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
@@ -3829,19 +3273,24 @@ public class Launcher extends Activity
}
}
- protected void showWorkspace(boolean animated) {
- showWorkspace(animated, null);
+ @Override
+ public void onStateTransitionHideSearchBar() {
+ // Hide the search bar
+ if (mSearchDropTargetBar != null) {
+ mSearchDropTargetBar.hideSearchBar(false /* animated */);
+ }
}
- protected void showWorkspace() {
- showWorkspace(true);
+ protected void showWorkspace(boolean animated) {
+ showWorkspace(animated, null);
}
void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
if (mState != State.WORKSPACE || mWorkspace.getState() != Workspace.State.NORMAL) {
boolean wasInSpringLoadedMode = (mState != State.WORKSPACE);
mWorkspace.setVisibility(View.VISIBLE);
- hideAppsCustomizeHelper(Workspace.State.NORMAL, animated, false, onCompleteRunnable);
+ mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.NORMAL,
+ animated, onCompleteRunnable);
// Show the search bar (only animate if we were showing the drop target bar in spring
// loaded mode)
@@ -3860,7 +3309,7 @@ public class Launcher extends Activity
// Resume the auto-advance of widgets
mUserPresent = true;
- updateRunning();
+ updateAutoAdvanceState();
// Send an accessibility event to announce the context change
getWindow().getDecorView()
@@ -3871,7 +3320,8 @@ public class Launcher extends Activity
void showOverviewMode(boolean animated) {
mWorkspace.setVisibility(View.VISIBLE);
- hideAppsCustomizeHelper(Workspace.State.OVERVIEW, animated, false, null);
+ mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.OVERVIEW,
+ animated, null /* onCompleteRunnable */);
mState = State.WORKSPACE;
onWorkspaceShown(animated);
}
@@ -3879,14 +3329,24 @@ public class Launcher extends Activity
public void onWorkspaceShown(boolean animated) {
}
- void showAllApps(boolean animated, AppsCustomizePagedView.ContentType contentType,
- boolean resetPageToZero) {
- if (mState != State.WORKSPACE) return;
+ /**
+ * Shows the apps view.
+ */
+ void showAppsView(boolean animated, boolean resetListToTop) {
+ if (resetListToTop) {
+ mAppsView.scrollToTop();
+ }
+ showAppsOrWidgets(animated, State.APPS);
+ }
+ /**
+ * Shows the widgets view.
+ */
+ void showWidgetsView(boolean animated, boolean resetPageToZero) {
if (resetPageToZero) {
mAppsCustomizeTabHost.reset();
}
- showAppsCustomizeHelper(animated, false, contentType);
+ showAppsOrWidgets(animated, State.WIDGETS);
mAppsCustomizeTabHost.post(new Runnable() {
@Override
public void run() {
@@ -3894,13 +3354,27 @@ public class Launcher extends Activity
mAppsCustomizeTabHost.requestFocus();
}
});
+ }
+
+ /**
+ * Sets up the transition to show the apps/widgets view.
+ */
+ private void showAppsOrWidgets(boolean animated, State toState) {
+ if (mState != State.WORKSPACE) return;
+ if (toState != State.APPS && toState != State.WIDGETS) return;
+
+ if (toState == State.APPS) {
+ mStateTransitionAnimation.startAnimationToAllApps(animated);
+ } else {
+ mStateTransitionAnimation.startAnimationToWidgets(animated);
+ }
// Change the state *after* we've called all the transition code
- mState = State.APPS_CUSTOMIZE;
+ mState = toState;
// Pause the auto-advance of widgets until we are out of AllApps
mUserPresent = false;
- updateRunning();
+ updateAutoAdvanceState();
closeFolder();
// Send an accessibility event to announce the context change
@@ -3909,15 +3383,19 @@ public class Launcher extends Activity
}
void enterSpringLoadedDragMode() {
- if (isAllAppsVisible()) {
- hideAppsCustomizeHelper(Workspace.State.SPRING_LOADED, true, true, null);
- mState = State.APPS_CUSTOMIZE_SPRING_LOADED;
+ if (mState == State.WORKSPACE || mState == State.APPS_SPRING_LOADED ||
+ mState == State.WIDGETS_SPRING_LOADED) {
+ return;
}
+
+ mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.SPRING_LOADED,
+ true /* animated */, null /* onCompleteRunnable */);
+ mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED;
}
void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay,
final Runnable onCompleteRunnable) {
- if (mState != State.APPS_CUSTOMIZE_SPRING_LOADED) return;
+ if (mState != State.APPS_SPRING_LOADED && mState != State.WIDGETS_SPRING_LOADED) return;
mHandler.postDelayed(new Runnable() {
@Override
@@ -3936,11 +3414,12 @@ public class Launcher extends Activity
}
void exitSpringLoadedDragMode() {
- if (mState == State.APPS_CUSTOMIZE_SPRING_LOADED) {
- final boolean animated = true;
- final boolean springLoaded = true;
- showAppsCustomizeHelper(animated, springLoaded);
- mState = State.APPS_CUSTOMIZE;
+ if (mState == State.APPS_SPRING_LOADED) {
+ mStateTransitionAnimation.startAnimationToAllApps(true /* animated */);
+ mState = State.APPS;
+ } else if (mState == State.WIDGETS_SPRING_LOADED) {
+ mStateTransitionAnimation.startAnimationToWidgets(true /* animated */);
+ mState = State.WIDGETS;
}
// Otherwise, we are not in spring loaded mode, so don't do anything.
}
@@ -4018,8 +3497,10 @@ public class Launcher extends Activity
final List<CharSequence> text = event.getText();
text.clear();
// Populate event with a fake title based on the current state.
- if (mState == State.APPS_CUSTOMIZE) {
- text.add(mAppsCustomizeTabHost.getContentTag());
+ if (mState == State.APPS) {
+ text.add("Apps");
+ } else if (mState == State.WIDGETS) {
+ text.add("Widgets");
} else {
text.add(getString(R.string.all_apps_home_button_label));
}
@@ -4242,8 +3723,8 @@ public class Launcher extends Activity
// Remove the extra empty screen
mWorkspace.removeExtraEmptyScreen(false, false);
- if (addedApps != null && mAppsCustomizeContent != null) {
- mAppsCustomizeContent.addApps(addedApps);
+ if (addedApps != null && mAppsView != null) {
+ mAppsView.addApps(addedApps);
}
}
@@ -4617,8 +4098,10 @@ public class Launcher extends Activity
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindAllApplications(final ArrayList<AppInfo> apps) {
+ if (mAppsView != null) {
+ mAppsView.setApps(apps);
+ }
if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.setApps(apps);
mAppsCustomizeContent.onPackagesUpdated(
LauncherModel.getSortedWidgetsAndShortcuts(this));
}
@@ -4642,8 +4125,8 @@ public class Launcher extends Activity
return;
}
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.updateApps(apps);
+ if (mAppsView != null) {
+ mAppsView.updateApps(apps);
}
}
@@ -4757,8 +4240,8 @@ public class Launcher extends Activity
}
// Update AllApps
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.removeApps(appInfos);
+ if (mAppsView != null) {
+ mAppsView.removeApps(appInfos);
}
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index cb9d12e01..3cada6fb8 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -3308,7 +3308,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
- // Returns a list of ResolveInfos/AppWindowInfos in sorted order
+ // Returns a list of ResolveInfos/AppWidgetInfos in sorted order
public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {
PackageManager packageManager = context.getPackageManager();
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
new file mode 100644
index 000000000..484ed5c30
--- /dev/null
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -0,0 +1,832 @@
+/*
+ * 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;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+
+import java.util.HashMap;
+
+/**
+ * TODO: figure out what kind of tests we can write for this
+ *
+ * Things to test when changing the following class.
+ * - Home from workspace
+ * - from center screen
+ * - from other screens
+ * - Home from all apps
+ * - from center screen
+ * - from other screens
+ * - Back from all apps
+ * - from center screen
+ * - from other screens
+ * - Launch app from workspace and quit
+ * - with back
+ * - with home
+ * - Launch app from all apps and quit
+ * - with back
+ * - with home
+ * - Go to a screen that's not the default, then all
+ * apps, and launch and app, and go back
+ * - with back
+ * -with home
+ * - On workspace, long press power and go back
+ * - with back
+ * - with home
+ * - On all apps, long press power and go back
+ * - with back
+ * - with home
+ * - On workspace, power off
+ * - On all apps, power off
+ * - Launch an app and turn off the screen while in that app
+ * - Go back with home key
+ * - Go back with back key TODO: make this not go to workspace
+ * - From all apps
+ * - From workspace
+ * - Enter and exit car mode (becuase it causes an extra configuration changed)
+ * - From all apps
+ * - From the center workspace
+ * - From another workspace
+ */
+public class LauncherStateTransitionAnimation {
+
+ /**
+ * Callbacks made during the state transition
+ */
+ interface Callbacks {
+ public void onStateTransitionHideSearchBar();
+ }
+
+ /**
+ * Private callbacks made during transition setup.
+ */
+ static abstract class PrivateTransitionCallbacks {
+ void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {}
+ void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {}
+ float getMaterialRevealViewFinalAlpha(View revealView) {
+ return 0;
+ }
+ float getMaterialRevealViewFinalXDrift(View revealView) {
+ return 0;
+ }
+ float getMaterialRevealViewFinalYDrift(View revealView) {
+ return 0;
+ }
+ float getMaterialRevealViewStartFinalRadius() {
+ return 0;
+ }
+ AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(View revealView,
+ View allAppsButtonView) {
+ return null;
+ }
+ }
+
+ public static final String TAG = "LauncherStateTransitionAnimation";
+
+ // Flags to determine how to set the layers on views before the transition animation
+ public static final int BUILD_LAYER = 0;
+ public static final int BUILD_AND_SET_LAYER = 1;
+ public static final int SINGLE_FRAME_DELAY = 16;
+
+ private Launcher mLauncher;
+ private Callbacks mCb;
+ private AnimatorSet mStateAnimation;
+
+ public LauncherStateTransitionAnimation(Launcher l, Callbacks cb) {
+ mLauncher = l;
+ mCb = cb;
+ }
+
+ /**
+ * Starts an animation to the apps view.
+ */
+ public void startAnimationToAllApps(final boolean animated) {
+ final AppsContainerView toView = mLauncher.getAppsView();
+ PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
+ private int[] mAllAppsToPanelDelta;
+
+ @Override
+ public void onRevealViewVisible(View revealView, View contentView,
+ View allAppsButtonView) {
+ toView.setBackground(null);
+ // Get the y delta between the center of the page and the center of the all apps
+ // button
+ mAllAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
+ allAppsButtonView, null);
+ }
+ @Override
+ public float getMaterialRevealViewFinalAlpha(View revealView) {
+ return 1f;
+ }
+ @Override
+ public float getMaterialRevealViewFinalXDrift(View revealView) {
+ return mAllAppsToPanelDelta[0];
+ }
+ @Override
+ public float getMaterialRevealViewFinalYDrift(View revealView) {
+ return mAllAppsToPanelDelta[1];
+ }
+ @Override
+ public float getMaterialRevealViewStartFinalRadius() {
+ int allAppsButtonSize = LauncherAppState.getInstance().
+ getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
+ return allAppsButtonSize / 2;
+ }
+ @Override
+ public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
+ final View revealView, final View allAppsButtonView) {
+ return new AnimatorListenerAdapter() {
+ public void onAnimationStart(Animator animation) {
+ allAppsButtonView.setVisibility(View.INVISIBLE);
+ }
+ public void onAnimationEnd(Animator animation) {
+ allAppsButtonView.setVisibility(View.VISIBLE);
+ }
+ };
+ }
+ };
+ startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, toView, toView.getContentView(),
+ toView.getRevealView(), null, animated, cb);
+ }
+
+ /**
+ * Starts an animation to the widgets view.
+ */
+ public void startAnimationToWidgets(final boolean animated) {
+ final AppsCustomizeTabHost 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.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);
+ }
+ @Override
+ public float getMaterialRevealViewFinalAlpha(View revealView) {
+ return 0.3f;
+ }
+ @Override
+ public float getMaterialRevealViewFinalYDrift(View revealView) {
+ return revealView.getMeasuredHeight() / 2;
+ }
+ };
+ startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, toView, toView.getContentView(),
+ toView.getRevealView(), toView.getPageIndicators(), animated, cb);
+ }
+
+ /**
+ * Starts and animation to the workspace from the current overlay view.
+ */
+ public void startAnimationToWorkspace(final Launcher.State fromState,
+ final Workspace.State toWorkspaceState, final boolean animated,
+ final Runnable onCompleteRunnable) {
+ if (toWorkspaceState != Workspace.State.NORMAL &&
+ toWorkspaceState != Workspace.State.SPRING_LOADED &&
+ toWorkspaceState != Workspace.State.OVERVIEW) {
+ Log.e(TAG, "Unexpected call to startAnimationToWorkspace");
+ }
+
+ if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) {
+ startAnimationToWorkspaceFromAllApps(fromState, toWorkspaceState, animated,
+ onCompleteRunnable);
+ } else {
+ startAnimationToWorkspaceFromWidgets(fromState, toWorkspaceState, animated,
+ onCompleteRunnable);
+ }
+ }
+
+ /**
+ * Creates and starts a new animation to a particular overlay view.
+ */
+ private void startAnimationToOverlay(final Workspace.State toWorkspaceState, final View toView,
+ final View contentView, final View revealView, final View pageIndicatorsView,
+ final boolean animated, final PrivateTransitionCallbacks pCb) {
+ final Resources res = mLauncher.getResources();
+ final boolean material = Utilities.isLmpOrAbove();
+ final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
+ final int itemsAlphaStagger =
+ res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
+
+ final View allAppsButtonView = mLauncher.getAllAppsButton();
+ final View fromView = mLauncher.getWorkspace();
+
+ final HashMap<View, Integer> layerViews = new HashMap<>();
+
+ // If for some reason our views aren't initialized, don't animate
+ boolean initialized = allAppsButtonView != null;
+
+ // Cancel the current animation
+ cancelAnimation();
+
+ // Create the workspace animation.
+ // NOTE: this call apparently also sets the state for the workspace if !animated
+ Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
+ toWorkspaceState, animated, layerViews);
+
+ if (animated && initialized) {
+ mStateAnimation = LauncherAnimUtils.createAnimatorSet();
+
+ // Setup the reveal view animation
+ int width = revealView.getMeasuredWidth();
+ int height = revealView.getMeasuredHeight();
+ float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+ revealView.setVisibility(View.VISIBLE);
+ revealView.setAlpha(0f);
+ revealView.setTranslationY(0f);
+ revealView.setTranslationX(0f);
+ pCb.onRevealViewVisible(revealView, contentView, allAppsButtonView);
+
+ // Calculate the final animation values
+ final float revealViewToAlpha;
+ final float revealViewToXDrift;
+ final float revealViewToYDrift;
+ if (material) {
+ revealViewToAlpha = pCb.getMaterialRevealViewFinalAlpha(revealView);
+ revealViewToYDrift = pCb.getMaterialRevealViewFinalYDrift(revealView);
+ revealViewToXDrift = pCb.getMaterialRevealViewFinalXDrift(revealView);
+ } else {
+ revealViewToAlpha = 0f;
+ revealViewToYDrift = 2 * height / 3;
+ revealViewToXDrift = 0;
+ }
+
+ // Create the animators
+ PropertyValuesHolder panelAlpha =
+ PropertyValuesHolder.ofFloat("alpha", revealViewToAlpha, 1f);
+ PropertyValuesHolder panelDriftY =
+ PropertyValuesHolder.ofFloat("translationY", revealViewToYDrift, 0);
+ PropertyValuesHolder panelDriftX =
+ PropertyValuesHolder.ofFloat("translationX", revealViewToXDrift, 0);
+ ObjectAnimator panelAlphaAndDrift = ObjectAnimator.ofPropertyValuesHolder(revealView,
+ panelAlpha, panelDriftY, panelDriftX);
+ panelAlphaAndDrift.setDuration(revealDuration);
+ panelAlphaAndDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+ // Play the animation
+ layerViews.put(revealView, BUILD_AND_SET_LAYER);
+ mStateAnimation.play(panelAlphaAndDrift);
+
+ // Setup the animation for the page indicators
+ if (pageIndicatorsView != null) {
+ pageIndicatorsView.setAlpha(0.01f);
+ ObjectAnimator indicatorsAlpha =
+ ObjectAnimator.ofFloat(pageIndicatorsView, "alpha", 1f);
+ indicatorsAlpha.setDuration(revealDuration);
+ mStateAnimation.play(indicatorsAlpha);
+ }
+
+ // Setup the animation for the content view
+ contentView.setVisibility(View.VISIBLE);
+ contentView.setAlpha(0f);
+ contentView.setTranslationY(revealViewToYDrift);
+ layerViews.put(contentView, BUILD_AND_SET_LAYER);
+
+ // Create the individual animators
+ ObjectAnimator pageDrift = ObjectAnimator.ofFloat(contentView, "translationY",
+ revealViewToYDrift, 0);
+ pageDrift.setDuration(revealDuration);
+ pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
+ pageDrift.setStartDelay(itemsAlphaStagger);
+ mStateAnimation.play(pageDrift);
+
+ ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 0f, 1f);
+ itemsAlpha.setDuration(revealDuration);
+ itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
+ itemsAlpha.setStartDelay(itemsAlphaStagger);
+ mStateAnimation.play(itemsAlpha);
+
+ if (material) {
+ // Animate the all apps button
+ float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
+ AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
+ revealView, allAppsButtonView);
+ Animator reveal = ViewAnimationUtils.createCircularReveal(revealView, width / 2,
+ height / 2, startRadius, revealRadius);
+ reveal.setDuration(revealDuration);
+ reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+ if (listener != null) {
+ reveal.addListener(listener);
+ }
+ mStateAnimation.play(reveal);
+ }
+
+ mStateAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ dispatchOnLauncherTransitionEnd(fromView, animated, false);
+ dispatchOnLauncherTransitionEnd(toView, animated, false);
+
+ // Hide the reveal view
+ revealView.setVisibility(View.INVISIBLE);
+ pCb.onAnimationComplete(revealView, contentView, allAppsButtonView);
+
+ // Disable all necessary layers
+ for (View v : layerViews.keySet()) {
+ if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+ v.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ }
+
+ // Hide the search bar
+ mCb.onStateTransitionHideSearchBar();
+
+ // This can hold unnecessary references to views.
+ mStateAnimation = null;
+ }
+
+ });
+
+ // Play the workspace animation
+ if (workspaceAnim != null) {
+ mStateAnimation.play(workspaceAnim);
+ }
+
+ // Dispatch the prepare transition signal
+ dispatchOnLauncherTransitionPrepare(fromView, animated, false);
+ dispatchOnLauncherTransitionPrepare(toView, animated, false);
+
+
+ final AnimatorSet stateAnimation = mStateAnimation;
+ final Runnable startAnimRunnable = new Runnable() {
+ public void run() {
+ // Check that mStateAnimation hasn't changed while
+ // we waited for a layout/draw pass
+ if (mStateAnimation != stateAnimation)
+ return;
+ dispatchOnLauncherTransitionStart(fromView, animated, false);
+ dispatchOnLauncherTransitionStart(toView, animated, false);
+
+ // Enable all necessary layers
+ for (View v : layerViews.keySet()) {
+ if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+ v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+ if (Utilities.isViewAttachedToWindow(v)) {
+ v.buildLayer();
+ }
+ }
+
+ // Focus the new view
+ toView.requestFocus();
+
+ mStateAnimation.start();
+ }
+ };
+
+ toView.bringToFront();
+ toView.setVisibility(View.VISIBLE);
+ toView.post(startAnimRunnable);
+ } else {
+ toView.setTranslationX(0.0f);
+ toView.setTranslationY(0.0f);
+ toView.setScaleX(1.0f);
+ toView.setScaleY(1.0f);
+ toView.setVisibility(View.VISIBLE);
+ toView.bringToFront();
+
+ // Show the content view
+ contentView.setVisibility(View.VISIBLE);
+
+ // Hide the search bar
+ mCb.onStateTransitionHideSearchBar();
+
+ dispatchOnLauncherTransitionPrepare(fromView, animated, false);
+ dispatchOnLauncherTransitionStart(fromView, animated, false);
+ dispatchOnLauncherTransitionEnd(fromView, animated, false);
+ dispatchOnLauncherTransitionPrepare(toView, animated, false);
+ dispatchOnLauncherTransitionStart(toView, animated, false);
+ dispatchOnLauncherTransitionEnd(toView, animated, false);
+ }
+ }
+
+ /**
+ * Starts and animation to the workspace from the apps view.
+ */
+ private void startAnimationToWorkspaceFromAllApps(final Launcher.State fromState,
+ final Workspace.State toWorkspaceState, final boolean animated,
+ final Runnable onCompleteRunnable) {
+ AppsContainerView appsView = mLauncher.getAppsView();
+ PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
+ int[] mAllAppsToPanelDelta;
+
+ @Override
+ public void onRevealViewVisible(View revealView, View contentView,
+ View allAppsButtonView) {
+ // Get the y delta between the center of the page and the center of the all apps
+ // button
+ mAllAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
+ allAppsButtonView, null);
+ }
+ @Override
+ public float getMaterialRevealViewFinalXDrift(View revealView) {
+ return mAllAppsToPanelDelta[0];
+ }
+ @Override
+ public float getMaterialRevealViewFinalYDrift(View revealView) {
+ return mAllAppsToPanelDelta[1];
+ }
+ @Override
+ float getMaterialRevealViewFinalAlpha(View revealView) {
+ // No alpha anim from all apps
+ return 1f;
+ }
+ @Override
+ float getMaterialRevealViewStartFinalRadius() {
+ int allAppsButtonSize = LauncherAppState.getInstance().
+ getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
+ return allAppsButtonSize / 2;
+ }
+ @Override
+ public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
+ final View revealView, final View allAppsButtonView) {
+ return new AnimatorListenerAdapter() {
+ public void onAnimationStart(Animator animation) {
+ // We set the alpha instead of visibility to ensure that the focus does not
+ // get taken from the all apps view
+ allAppsButtonView.setVisibility(View.VISIBLE);
+ allAppsButtonView.setAlpha(0f);
+ }
+ public void onAnimationEnd(Animator animation) {
+ // Hide the reveal view
+ revealView.setVisibility(View.INVISIBLE);
+
+ // Show the all apps button, and focus it
+ allAppsButtonView.setAlpha(1f);
+ }
+ };
+ }
+ };
+ startAnimationToWorkspaceFromOverlay(toWorkspaceState, appsView, appsView.getContentView(),
+ appsView.getRevealView(), null /* pageIndicatorsView */, animated,
+ onCompleteRunnable, cb);
+ }
+
+ /**
+ * Starts and animation to the workspace from the widgets view.
+ */
+ private void startAnimationToWorkspaceFromWidgets(final Launcher.State fromState,
+ final Workspace.State toWorkspaceState, final boolean animated,
+ final Runnable onCompleteRunnable) {
+ AppsCustomizeTabHost 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.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;
+ }
+ @Override
+ float getMaterialRevealViewFinalAlpha(View revealView) {
+ return 0.4f;
+ }
+ @Override
+ public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
+ final View revealView, final View allAppsButtonView) {
+ return new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ // Hide the reveal view
+ revealView.setVisibility(View.INVISIBLE);
+ }
+ };
+ }
+ };
+ startAnimationToWorkspaceFromOverlay(toWorkspaceState, widgetsView,
+ widgetsView.getContentView(), widgetsView.getRevealView(),
+ widgetsView.getPageIndicators(), animated, onCompleteRunnable, cb);
+ }
+
+ /**
+ * Creates and starts a new animation to the workspace.
+ */
+ private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState,
+ final View fromView, final View contentView, final View revealView,
+ final View pageIndicatorsView, final boolean animated,
+ final Runnable onCompleteRunnable, final PrivateTransitionCallbacks pCb) {
+ final Resources res = mLauncher.getResources();
+ final boolean material = Utilities.isLmpOrAbove();
+ final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
+ final int itemsAlphaStagger =
+ res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
+
+ final View allAppsButtonView = mLauncher.getAllAppsButton();
+ final View toView = mLauncher.getWorkspace();
+
+ final HashMap<View, Integer> layerViews = new HashMap<>();
+
+ // If for some reason our views aren't initialized, don't animate
+ boolean initialized = allAppsButtonView != null;
+
+ // Cancel the current animation
+ cancelAnimation();
+
+ // Create the workspace animation.
+ // NOTE: this call apparently also sets the state for the workspace if !animated
+ Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
+ toWorkspaceState, animated, layerViews);
+
+ if (animated && initialized) {
+ mStateAnimation = LauncherAnimUtils.createAnimatorSet();
+
+ // Play the workspace animation
+ if (workspaceAnim != null) {
+ mStateAnimation.play(workspaceAnim);
+ }
+
+ // hideAppsCustomizeHelper is called in some cases when it is already hidden
+ // don't perform all these no-op animations. In particularly, this was causing
+ // the all-apps button to pop in and out.
+ if (fromView.getVisibility() == View.VISIBLE) {
+ int width = revealView.getMeasuredWidth();
+ int height = revealView.getMeasuredHeight();
+ float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+ revealView.setVisibility(View.VISIBLE);
+ revealView.setAlpha(1f);
+ revealView.setTranslationY(0);
+ layerViews.put(revealView, BUILD_AND_SET_LAYER);
+ pCb.onRevealViewVisible(revealView, contentView, allAppsButtonView);
+
+ // Calculate the final animation values
+ final float revealViewToXDrift;
+ final float revealViewToYDrift;
+ if (material) {
+ revealViewToYDrift = pCb.getMaterialRevealViewFinalYDrift(revealView);
+ revealViewToXDrift = pCb.getMaterialRevealViewFinalXDrift(revealView);
+ } else {
+ revealViewToYDrift = 2 * height / 3;
+ revealViewToXDrift = 0;
+ }
+
+ // The vertical motion of the apps panel should be delayed by one frame
+ // from the conceal animation in order to give the right feel. We correspondingly
+ // shorten the duration so that the slide and conceal end at the same time.
+ TimeInterpolator decelerateInterpolator = material ?
+ new LogDecelerateInterpolator(100, 0) :
+ new DecelerateInterpolator(1f);
+ ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY",
+ 0, revealViewToYDrift);
+ panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
+ panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
+ panelDriftY.setInterpolator(decelerateInterpolator);
+ mStateAnimation.play(panelDriftY);
+
+ ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX",
+ 0, revealViewToXDrift);
+ panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
+ panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
+ panelDriftX.setInterpolator(decelerateInterpolator);
+ mStateAnimation.play(panelDriftX);
+
+ // Setup animation for the reveal panel alpha
+ final float revealViewToAlpha = !material ? 0f :
+ pCb.getMaterialRevealViewFinalAlpha(revealView);
+ if (revealViewToAlpha != 1f) {
+ ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha",
+ 1f, revealViewToAlpha);
+ panelAlpha.setDuration(material ? revealDuration : 150);
+ panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
+ panelAlpha.setInterpolator(decelerateInterpolator);
+ mStateAnimation.play(panelAlpha);
+ }
+
+ // Setup the animation for the content view
+ layerViews.put(contentView, BUILD_AND_SET_LAYER);
+
+ // Create the individual animators
+ ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(contentView, "translationY",
+ 0, revealViewToYDrift);
+ contentView.setTranslationY(0);
+ pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
+ pageDrift.setInterpolator(decelerateInterpolator);
+ pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
+ mStateAnimation.play(pageDrift);
+
+ contentView.setAlpha(1f);
+ ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(contentView, "alpha", 1f, 0f);
+ itemsAlpha.setDuration(100);
+ itemsAlpha.setInterpolator(decelerateInterpolator);
+ mStateAnimation.play(itemsAlpha);
+
+ // Setup the page indicators animation
+ if (pageIndicatorsView != null) {
+ pageIndicatorsView.setAlpha(1f);
+ ObjectAnimator indicatorsAlpha =
+ LauncherAnimUtils.ofFloat(pageIndicatorsView, "alpha", 0f);
+ indicatorsAlpha.setDuration(revealDuration);
+ indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
+ mStateAnimation.play(indicatorsAlpha);
+ }
+
+ if (material) {
+ // Animate the all apps button
+ float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
+ AnimatorListenerAdapter listener =
+ pCb.getMaterialRevealViewAnimatorListener(revealView, allAppsButtonView);
+ Animator reveal =
+ LauncherAnimUtils.createCircularReveal(revealView, width / 2,
+ height / 2, revealRadius, finalRadius);
+ reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+ reveal.setDuration(revealDuration);
+ reveal.setStartDelay(itemsAlphaStagger);
+ if (listener != null) {
+ reveal.addListener(listener);
+ }
+ mStateAnimation.play(reveal);
+ }
+
+ dispatchOnLauncherTransitionPrepare(fromView, animated, true);
+ dispatchOnLauncherTransitionPrepare(toView, animated, true);
+ }
+
+ mStateAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ fromView.setVisibility(View.GONE);
+ dispatchOnLauncherTransitionEnd(fromView, animated, true);
+ dispatchOnLauncherTransitionEnd(toView, animated, true);
+
+ // Run any queued runnables
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
+
+ // Animation complete callback
+ pCb.onAnimationComplete(revealView, contentView, allAppsButtonView);
+
+ // Disable all necessary layers
+ for (View v : layerViews.keySet()) {
+ if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+ v.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ }
+
+ // Reset page transforms
+ if (contentView != null) {
+ contentView.setTranslationX(0);
+ contentView.setTranslationY(0);
+ contentView.setAlpha(1);
+ }
+
+ // This can hold unnecessary references to views.
+ mStateAnimation = null;
+ }
+ });
+
+ final AnimatorSet stateAnimation = mStateAnimation;
+ final Runnable startAnimRunnable = new Runnable() {
+ public void run() {
+ // Check that mStateAnimation hasn't changed while
+ // we waited for a layout/draw pass
+ if (mStateAnimation != stateAnimation)
+ return;
+ dispatchOnLauncherTransitionStart(fromView, animated, false);
+ dispatchOnLauncherTransitionStart(toView, animated, false);
+
+ // Enable all necessary layers
+ for (View v : layerViews.keySet()) {
+ if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+ v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+ if (Utilities.isLmpOrAbove()) {
+ v.buildLayer();
+ }
+ }
+ mStateAnimation.start();
+ }
+ };
+ fromView.post(startAnimRunnable);
+ } else {
+ fromView.setVisibility(View.GONE);
+ dispatchOnLauncherTransitionPrepare(fromView, animated, true);
+ dispatchOnLauncherTransitionStart(fromView, animated, true);
+ dispatchOnLauncherTransitionEnd(fromView, animated, true);
+ dispatchOnLauncherTransitionPrepare(toView, animated, true);
+ dispatchOnLauncherTransitionStart(toView, animated, true);
+ dispatchOnLauncherTransitionEnd(toView, animated, true);
+
+ // Run any queued runnables
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
+ }
+ }
+
+
+ /**
+ * Dispatches the prepare-transition event to suitable views.
+ */
+ void dispatchOnLauncherTransitionPrepare(View v, boolean animated, boolean toWorkspace) {
+ if (v instanceof LauncherTransitionable) {
+ ((LauncherTransitionable) v).onLauncherTransitionPrepare(mLauncher, animated,
+ toWorkspace);
+ }
+ }
+
+ /**
+ * Dispatches the start-transition event to suitable views.
+ */
+ void dispatchOnLauncherTransitionStart(View v, boolean animated, boolean toWorkspace) {
+ if (v instanceof LauncherTransitionable) {
+ ((LauncherTransitionable) v).onLauncherTransitionStart(mLauncher, animated,
+ toWorkspace);
+ }
+
+ // Update the workspace transition step as well
+ dispatchOnLauncherTransitionStep(v, 0f);
+ }
+
+ /**
+ * Dispatches the step-transition event to suitable views.
+ */
+ void dispatchOnLauncherTransitionStep(View v, float t) {
+ if (v instanceof LauncherTransitionable) {
+ ((LauncherTransitionable) v).onLauncherTransitionStep(mLauncher, t);
+ }
+ }
+
+ /**
+ * Dispatches the end-transition event to suitable views.
+ */
+ void dispatchOnLauncherTransitionEnd(View v, boolean animated, boolean toWorkspace) {
+ if (v instanceof LauncherTransitionable) {
+ ((LauncherTransitionable) v).onLauncherTransitionEnd(mLauncher, animated,
+ toWorkspace);
+ }
+
+ // Update the workspace transition step as well
+ dispatchOnLauncherTransitionStep(v, 1f);
+ }
+
+ /**
+ * Cancels the current animation.
+ */
+ private void cancelAnimation() {
+ if (mStateAnimation != null) {
+ mStateAnimation.setDuration(0);
+ mStateAnimation.cancel();
+ mStateAnimation = null;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/launcher3/PagedViewWithDraggableItems.java b/src/com/android/launcher3/PagedViewWithDraggableItems.java
index 0e593698d..f0743cf1c 100644
--- a/src/com/android/launcher3/PagedViewWithDraggableItems.java
+++ b/src/com/android/launcher3/PagedViewWithDraggableItems.java
@@ -109,7 +109,7 @@ public abstract class PagedViewWithDraggableItems extends PagedView
// 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.isAllAppsVisible() ||
+ if (!mLauncher.isWidgetsViewVisible() ||
mLauncher.getWorkspace().isSwitchingState()) return false;
// Return if global dragging is not enabled
if (!mLauncher.isDraggingEnabled()) return false;
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index d963f2db9..312814039 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -131,8 +131,8 @@ public class WidgetPreviewLoader {
private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
- private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>();
- private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>();
+ private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>();
+ private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<>();
private final Context mContext;
private final int mAppIconSize;
diff --git a/src/com/android/launcher3/WidgetsContainerView.java b/src/com/android/launcher3/WidgetsContainerView.java
new file mode 100644
index 000000000..d0dd733a6
--- /dev/null
+++ b/src/com/android/launcher3/WidgetsContainerView.java
@@ -0,0 +1,88 @@
+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) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ }
+}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 3b293f95b..a59e25e08 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1528,7 +1528,7 @@ public class Workspace extends SmoothPagedView
@Override
public void announceForAccessibility(CharSequence text) {
// Don't announce if apps is on top of us.
- if (!mLauncher.isAllAppsVisible()) {
+ if (!mLauncher.isAppsViewVisible()) {
super.announceForAccessibility(text);
}
}
@@ -1816,7 +1816,7 @@ public class Workspace extends SmoothPagedView
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
- if (!mLauncher.isAllAppsVisible()) {
+ if (!mLauncher.isAppsViewVisible()) {
final Folder openFolder = getOpenFolder();
if (openFolder != null) {
return openFolder.requestFocus(direction, previouslyFocusedRect);
@@ -1837,7 +1837,7 @@ public class Workspace extends SmoothPagedView
@Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
- if (!mLauncher.isAllAppsVisible()) {
+ if (!mLauncher.isAppsViewVisible()) {
final Folder openFolder = getOpenFolder();
if (openFolder != null) {
openFolder.addFocusables(views, direction);
@@ -2046,8 +2046,7 @@ public class Workspace extends SmoothPagedView
// If this is a text view, use its drawable instead
if (v instanceof TextView) {
- TextView tv = (TextView) v;
- Drawable d = tv.getCompoundDrawables()[1];
+ Drawable d = getTextViewIcon((TextView) v);
Rect bounds = getDrawableBounds(d);
bmpWidth = bounds.width();
bmpHeight = bounds.height();
@@ -2348,7 +2347,7 @@ public class Workspace extends SmoothPagedView
cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
} else {
if (layerViews != null) {
- layerViews.put(cl, Launcher.BUILD_LAYER);
+ layerViews.put(cl, LauncherStateTransitionAnimation.BUILD_LAYER);
}
if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
LauncherViewPropertyAnimator alphaAnim =
@@ -2400,8 +2399,8 @@ public class Workspace extends SmoothPagedView
if (layerViews != null) {
// If layerViews is not null, we add these views, and indicate that
// the caller can manage layer state.
- layerViews.put(hotseat, Launcher.BUILD_AND_SET_LAYER);
- layerViews.put(overviewPanel, Launcher.BUILD_AND_SET_LAYER);
+ layerViews.put(hotseat, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+ layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
} else {
// Otherwise let the animator handle layer management.
hotseatAlpha.withLayer();
@@ -2430,7 +2429,7 @@ public class Workspace extends SmoothPagedView
if (layerViews != null) {
// If layerViews is not null, we add these views, and indicate that
// the caller can manage layer state.
- layerViews.put(searchBar, Launcher.BUILD_AND_SET_LAYER);
+ layerViews.put(searchBar, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
} else {
// Otherwise let the animator handle layer management.
searchBarAlpha.withLayer();
@@ -2584,6 +2583,19 @@ public class Workspace extends SmoothPagedView
}
/**
+ * Returns the drawable for the given text view.
+ */
+ public static Drawable getTextViewIcon(TextView tv) {
+ final Drawable[] drawables = tv.getCompoundDrawables();
+ for (int i = 0; i < drawables.length; i++) {
+ if (drawables[i] != null) {
+ return drawables[i];
+ }
+ }
+ return null;
+ }
+
+ /**
* Draw the View v into the given Canvas.
*
* @param v the view to draw
@@ -2598,7 +2610,7 @@ public class Workspace extends SmoothPagedView
destCanvas.save();
if (v instanceof TextView) {
- Drawable d = ((TextView) v).getCompoundDrawables()[1];
+ Drawable d = getTextViewIcon((TextView) v);
Rect bounds = getDrawableBounds(d);
clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);
destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);
@@ -2635,7 +2647,7 @@ public class Workspace extends SmoothPagedView
int padding = expectedPadding.get();
if (v instanceof TextView) {
- Drawable d = ((TextView) v).getCompoundDrawables()[1];
+ Drawable d = getTextViewIcon((TextView) v);
Rect bounds = getDrawableBounds(d);
b = Bitmap.createBitmap(bounds.width() + padding,
bounds.height() + padding, Bitmap.Config.ARGB_8888);
@@ -2716,11 +2728,12 @@ public class Workspace extends SmoothPagedView
beginDragShared(child, this, accessible);
}
- public void beginDragShared(View child, DragSource source) {
- beginDragShared(child, source, false);
+ public void beginDragShared(View child, DragSource source, boolean accessible) {
+ beginDragShared(child, new Point(), source, accessible);
}
- public void beginDragShared(View child, DragSource source, boolean accessible) {
+ public void beginDragShared(View child, Point relativeTouchPos, DragSource source,
+ boolean accessible) {
child.clearFocus();
child.setPressed(false);
@@ -2745,11 +2758,23 @@ public class Workspace extends SmoothPagedView
Point dragVisualizeOffset = null;
Rect dragRect = null;
if (child instanceof BubbleTextView) {
+ BubbleTextView icon = (BubbleTextView) child;
int iconSize = grid.iconSizePx;
int top = child.getPaddingTop();
int left = (bmpWidth - iconSize) / 2;
int right = left + iconSize;
int bottom = top + iconSize;
+ if (icon.isLayoutHorizontal()) {
+ // If the layout is horizontal, then if we are just picking up the icon, then just
+ // use the child position since the icon is top-left aligned. Otherwise, offset
+ // the drag layer position horizontally so that the icon is under the current
+ // touch position.
+ if (icon.getIcon().getBounds().contains(relativeTouchPos.x, relativeTouchPos.y)) {
+ dragLayerX = Math.round(mTempXY[0]);
+ } else {
+ dragLayerX = Math.round(mTempXY[0] + relativeTouchPos.x - (bmpWidth / 2));
+ }
+ }
dragLayerY += top;
// Note: The drag region is used to calculate drag layer offsets, but the
// dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
@@ -2831,18 +2856,6 @@ public class Workspace extends SmoothPagedView
tmpB.recycle();
}
- void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,
- int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
- View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
-
- final int[] cellXY = new int[2];
- target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
- addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
-
- LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],
- cellXY[1]);
- }
-
public boolean transitionStateShouldAllowDrop() {
return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&
(mState == State.NORMAL || mState == State.SPRING_LOADED));
@@ -4769,7 +4782,7 @@ public class Workspace extends SmoothPagedView
updates.contains(info)) {
ShortcutInfo si = (ShortcutInfo) info;
BubbleTextView shortcut = (BubbleTextView) v;
- boolean oldPromiseState = shortcut.getCompoundDrawables()[1]
+ boolean oldPromiseState = getTextViewIcon(shortcut)
instanceof PreloadIconDrawable;
shortcut.applyFromShortcutInfo(si, mIconCache, true,
si.isPromise() != oldPromiseState);