OSDN Git Service

Implementation of folder animation changes as per cm-13.0
authorVineet Patil <vpatil@cyngn.com>
Tue, 17 Nov 2015 22:23:05 +0000 (14:23 -0800)
committerVineet Patil <vpatil@cyngn.com>
Wed, 18 Nov 2015 21:39:02 +0000 (13:39 -0800)
Folder animations in parity with cm.

Folder Layout Revision

Updated the folder layout to reflect design revisions based on community feedback

Change-Id: Ica1bb796dfccf779a954cf0903a1ae94a010ea1a

Conflicts:
res/drawable-hdpi/folder_bg.9.png
res/drawable-hdpi/folder_fill_highlight.9.png
res/drawable-mdpi/folder_bg.9.png
res/drawable-mdpi/folder_fill_highlight.9.png
res/drawable-xhdpi/folder_bg.9.png
res/drawable-xhdpi/folder_fill_highlight.9.png
res/drawable-xxhdpi/folder_bg.9.png
res/drawable-xxhdpi/folder_fill_highlight.9.png
res/layout-land/launcher.xml
res/layout-port/launcher.xml
res/layout-sw720dp/launcher.xml
res/layout/user_folder.xml
res/values/dimens.xml
src/com/android/launcher3/Folder.java
src/com/android/launcher3/FolderIcon.java
src/com/android/launcher3/Launcher.java

Folder animation changes as per cm-13.0

Change-Id: I019511a58bd9f6a60a3c9b68c826726881cec83f

Implementing folder animations

Change-Id: I83f17c996ecc894ce22fd195b9b33caf58e2e822

38 files changed:
res/anim/drop_down.xml [new file with mode: 0644]
res/anim/enter_from_left.xml [new file with mode: 0644]
res/anim/enter_from_right.xml [new file with mode: 0644]
res/anim/exit_out_left.xml [new file with mode: 0644]
res/anim/exit_out_right.xml [new file with mode: 0644]
res/anim/fade_in_fast.xml [new file with mode: 0644]
res/anim/fade_out_fast.xml [new file with mode: 0644]
res/drawable-hdpi/folder_bg.9.png [new file with mode: 0644]
res/drawable-hdpi/folder_bg_opaque.9.png [new file with mode: 0755]
res/drawable-hdpi/folder_fill_highlight.9.png [new file with mode: 0644]
res/drawable-mdpi/folder_bg.9.png [new file with mode: 0644]
res/drawable-mdpi/folder_bg_opaque.9.png [new file with mode: 0755]
res/drawable-mdpi/folder_fill_highlight.9.png [new file with mode: 0644]
res/drawable-xhdpi/folder_bg.9.png [new file with mode: 0644]
res/drawable-xhdpi/folder_bg_opaque.9.png [new file with mode: 0755]
res/drawable-xhdpi/folder_fill_highlight.9.png [new file with mode: 0644]
res/drawable-xxhdpi/folder_bg.9.png [new file with mode: 0644]
res/drawable-xxhdpi/folder_bg_opaque.9.png [new file with mode: 0755]
res/drawable-xxhdpi/folder_fill_highlight.9.png [new file with mode: 0644]
res/drawable/folder_container.xml [new file with mode: 0644]
res/drawable/folder_locked.xml [new file with mode: 0644]
res/drawable/folder_unlocked.xml [new file with mode: 0644]
res/layout-land/launcher.xml
res/layout-port/launcher.xml
res/layout-sw720dp/launcher.xml
res/layout/folder_icon.xml
res/layout/user_folder.xml
res/values/attrs.xml
res/values/dimens.xml
res/values/strings.xml
res/values/styles.xml
src/com/android/launcher3/CellLayout.java
src/com/android/launcher3/Folder.java
src/com/android/launcher3/FolderIcon.java
src/com/android/launcher3/FolderInfo.java
src/com/android/launcher3/InsettableFrameLayout.java
src/com/android/launcher3/Launcher.java
src/com/android/launcher3/LauncherSettings.java

diff --git a/res/anim/drop_down.xml b/res/anim/drop_down.xml
new file mode 100644 (file)
index 0000000..49059a0
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@android:interpolator/accelerate_decelerate">
+    <scale
+       android:fromXScale="1.0"
+       android:toXScale="1.0"
+       android:fromYScale="2.5"
+       android:toYScale="1.0"
+       android:pivotX="50%"
+       android:pivotY="50%"
+       android:duration="300"
+       android:fillBefore="false" />
+</set>
diff --git a/res/anim/enter_from_left.xml b/res/anim/enter_from_left.xml
new file mode 100644 (file)
index 0000000..e2bdbdd
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:duration="300"
+            android:propertyName="x"
+            android:valueFrom="-1000"
+            android:valueTo="0"
+            android:valueType="floatType" />
+</set>
diff --git a/res/anim/enter_from_right.xml b/res/anim/enter_from_right.xml
new file mode 100644 (file)
index 0000000..02a56c7
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:duration="300"
+            android:propertyName="x"
+            android:valueFrom="1000"
+            android:valueTo="0"
+            android:valueType="floatType" />
+</set>
diff --git a/res/anim/exit_out_left.xml b/res/anim/exit_out_left.xml
new file mode 100644 (file)
index 0000000..eae925a
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:duration="300"
+            android:propertyName="x"
+            android:valueFrom="0"
+            android:valueTo="-1000"
+            android:valueType="floatType" />
+</set>
+
diff --git a/res/anim/exit_out_right.xml b/res/anim/exit_out_right.xml
new file mode 100644 (file)
index 0000000..7345c94
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:duration="300"
+            android:propertyName="x"
+            android:valueFrom="0"
+            android:valueTo="1000"
+            android:valueType="floatType" />
+</set>
diff --git a/res/anim/fade_in_fast.xml b/res/anim/fade_in_fast.xml
new file mode 100644 (file)
index 0000000..4fa9847
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+    android:interpolator="@android:anim/accelerate_interpolator"
+
+    android:fromAlpha="0.0"
+    android:toAlpha="1.0"
+
+    android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/res/anim/fade_out_fast.xml b/res/anim/fade_out_fast.xml
new file mode 100644 (file)
index 0000000..a061a6c
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+    android:interpolator="@android:anim/accelerate_interpolator"
+
+    android:fromAlpha="1.0"
+    android:toAlpha="0.0"
+
+    android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/res/drawable-hdpi/folder_bg.9.png b/res/drawable-hdpi/folder_bg.9.png
new file mode 100644 (file)
index 0000000..ee0090c
Binary files /dev/null and b/res/drawable-hdpi/folder_bg.9.png differ
diff --git a/res/drawable-hdpi/folder_bg_opaque.9.png b/res/drawable-hdpi/folder_bg_opaque.9.png
new file mode 100755 (executable)
index 0000000..08e152e
Binary files /dev/null and b/res/drawable-hdpi/folder_bg_opaque.9.png differ
diff --git a/res/drawable-hdpi/folder_fill_highlight.9.png b/res/drawable-hdpi/folder_fill_highlight.9.png
new file mode 100644 (file)
index 0000000..b82302b
Binary files /dev/null and b/res/drawable-hdpi/folder_fill_highlight.9.png differ
diff --git a/res/drawable-mdpi/folder_bg.9.png b/res/drawable-mdpi/folder_bg.9.png
new file mode 100644 (file)
index 0000000..4039da5
Binary files /dev/null and b/res/drawable-mdpi/folder_bg.9.png differ
diff --git a/res/drawable-mdpi/folder_bg_opaque.9.png b/res/drawable-mdpi/folder_bg_opaque.9.png
new file mode 100755 (executable)
index 0000000..673d740
Binary files /dev/null and b/res/drawable-mdpi/folder_bg_opaque.9.png differ
diff --git a/res/drawable-mdpi/folder_fill_highlight.9.png b/res/drawable-mdpi/folder_fill_highlight.9.png
new file mode 100644 (file)
index 0000000..7c6a0d4
Binary files /dev/null and b/res/drawable-mdpi/folder_fill_highlight.9.png differ
diff --git a/res/drawable-xhdpi/folder_bg.9.png b/res/drawable-xhdpi/folder_bg.9.png
new file mode 100644 (file)
index 0000000..1fbe1d8
Binary files /dev/null and b/res/drawable-xhdpi/folder_bg.9.png differ
diff --git a/res/drawable-xhdpi/folder_bg_opaque.9.png b/res/drawable-xhdpi/folder_bg_opaque.9.png
new file mode 100755 (executable)
index 0000000..42a1e1d
Binary files /dev/null and b/res/drawable-xhdpi/folder_bg_opaque.9.png differ
diff --git a/res/drawable-xhdpi/folder_fill_highlight.9.png b/res/drawable-xhdpi/folder_fill_highlight.9.png
new file mode 100644 (file)
index 0000000..f5f0bd0
Binary files /dev/null and b/res/drawable-xhdpi/folder_fill_highlight.9.png differ
diff --git a/res/drawable-xxhdpi/folder_bg.9.png b/res/drawable-xxhdpi/folder_bg.9.png
new file mode 100644 (file)
index 0000000..3b2bc42
Binary files /dev/null and b/res/drawable-xxhdpi/folder_bg.9.png differ
diff --git a/res/drawable-xxhdpi/folder_bg_opaque.9.png b/res/drawable-xxhdpi/folder_bg_opaque.9.png
new file mode 100755 (executable)
index 0000000..25a4fff
Binary files /dev/null and b/res/drawable-xxhdpi/folder_bg_opaque.9.png differ
diff --git a/res/drawable-xxhdpi/folder_fill_highlight.9.png b/res/drawable-xxhdpi/folder_fill_highlight.9.png
new file mode 100644 (file)
index 0000000..4dc29f4
Binary files /dev/null and b/res/drawable-xxhdpi/folder_fill_highlight.9.png differ
diff --git a/res/drawable/folder_container.xml b/res/drawable/folder_container.xml
new file mode 100644 (file)
index 0000000..b0a1c84
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="72dp"
+        android:width="72dp"
+        android:viewportHeight="72"
+        android:viewportWidth="72">
+
+    <group
+        android:name="folder_container">
+        <path
+            android:name="folder_path"
+            android:pathData="  M6,4
+                                h60
+                                c1.2,0 2,0.8 2,2
+                                v60
+                                c0,1.2 -0.8,2 -2,2
+                                h-60
+                                c-1.2,0 -2,-0.8 -2,-2
+                                v-60
+                                c0,-1.2 0.8,-2 2,-2
+                                z"
+            android:fillColor="#ff524e5e"/>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/res/drawable/folder_locked.xml b/res/drawable/folder_locked.xml
new file mode 100644 (file)
index 0000000..8b88789
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+   android:width="24dp"
+   android:height="24dp"
+   android:viewportWidth="24"
+   android:viewportHeight="24">
+
+   <path
+       android:fillColor="#fafafa"
+       android:pathData="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1 .9 2 2
+2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6-5.1c1.71 0 3.1 1.39 3.1
+3.1v2H9V6h-.1c0-1.71 1.39-3.1 3.1-3.1zM18 20H6V10h12v10zm-6-3c1.1 0 2-.9
+2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z" />
+</vector>
diff --git a/res/drawable/folder_unlocked.xml b/res/drawable/folder_unlocked.xml
new file mode 100644 (file)
index 0000000..d34d9b7
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+   android:width="24dp"
+   android:height="24dp"
+   android:viewportWidth="24"
+   android:viewportHeight="24">
+
+   <path
+       android:fillColor="#fafafa"
+       android:pathData="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7
+3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2
+2v10c0 1.1 .9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm0 12H6V10h12v10z" />
+</vector>
index 6500ebc..3a93365 100644 (file)
     android:id="@+id/launcher"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
+    android:fitsSystemWindows="true"
+    android:background="@drawable/workspace_bg">
+
+    <FrameLayout
+        android:id="@+id/reveal_fake_page_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible"
+        android:alpha="1.0"
+        android:clipToPadding="false">
+
+        <ImageView
+            android:id="@+id/reveal_fake_folder_icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:visibility="invisible"
+            android:background="@drawable/folder_bg_opaque"/>
+    </FrameLayout>
 
     <com.android.launcher3.DragLayer
         android:id="@+id/drag_layer"
index d0772ee..cbdb001 100644 (file)
 <com.android.launcher3.LauncherRootView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    xmlns:insettable="http://schemas.android.com/apk/res-auto"
 
     android:id="@+id/launcher"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
+    android:fitsSystemWindows="true"
+    android:background="@drawable/workspace_bg">
+
+    <FrameLayout
+        android:id="@+id/reveal_fake_page_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible"
+        android:alpha="1.0"
+        insettable:layout_ignoreInsets="true"
+        android:clipToPadding="false">
+
+        <ImageView
+            android:id="@+id/reveal_fake_folder_icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:visibility="invisible"
+            android:background="@drawable/folder_bg_opaque"/>
+    </FrameLayout>
 
     <com.android.launcher3.DragLayer
         android:id="@+id/drag_layer"
index 802922e..c448e76 100644 (file)
     android:id="@+id/launcher"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
+    android:fitsSystemWindows="true"
+    android:background="@drawable/workspace_bg">
+
+    <FrameLayout
+        android:id="@+id/reveal_fake_page_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible"
+        android:alpha="1.0"
+        android:clipToPadding="false">
+
+        <ImageView
+            android:id="@+id/reveal_fake_folder_icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:visibility="invisible"
+            android:background="@drawable/folder_bg_opaque"/>
+    </FrameLayout>
 
     <com.android.launcher3.DragLayer
         android:id="@+id/drag_layer"
index 237af68..5e29a1a 100644 (file)
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:focusable="true" >
-    <ImageView
+    <RelativeLayout
         android:id="@+id/preview_background"
-        android:layout_gravity="center_horizontal"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:antialias="true"
-        android:src="@drawable/portal_ring_inner"/>
+        android:layout_width="@dimen/folder_icon"
+        android:layout_height="@dimen/folder_icon"
+        android:layout_gravity="center_horizontal|top"
+        android:background="@drawable/folder_bg" >
+        <ImageView
+            android:id="@+id/folder_lock_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:src="@drawable/folder_locked"
+            android:scaleType="center"
+            android:visibility="invisible" />
+        <ImageView
+            android:id="@+id/app_0"
+            android:layout_width="@dimen/folder_icon_app_preview"
+            android:layout_height="@dimen/folder_icon_app_preview"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentTop="true"
+            android:antialias="true"/>
+        <ImageView
+            android:id="@+id/app_1"
+            android:layout_width="@dimen/folder_icon_app_preview"
+            android:layout_height="@dimen/folder_icon_app_preview"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:antialias="true"/>
+        <ImageView
+            android:id="@+id/app_2"
+            android:layout_width="@dimen/folder_icon_app_preview"
+            android:layout_height="@dimen/folder_icon_app_preview"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentBottom="true"
+            android:antialias="true"/>
+        <ImageView
+            android:id="@+id/app_3"
+            android:layout_width="@dimen/folder_icon_app_preview"
+            android:layout_height="@dimen/folder_icon_app_preview"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:antialias="true"/>
+    </RelativeLayout>
+
     <com.android.launcher3.BubbleTextView
         style="@style/Icon"
         android:id="@+id/folder_icon_name"
-        android:layout_gravity="top"
+        android:layout_gravity="bottom"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
 </com.android.launcher3.FolderIcon>
index 252ebf0..2152a99 100644 (file)
@@ -18,7 +18,7 @@
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:background="@drawable/quantum_panel"
+    android:background="@drawable/folder_bg"
     android:elevation="5dp"
     android:orientation="vertical" >
 
@@ -67,7 +67,7 @@
             android:paddingBottom="8dp"
             android:paddingTop="4dp"
             android:singleLine="true"
-            android:textColor="#ff777777"
+            android:textColor="@color/workspace_icon_text_color"
             android:textColorHighlight="#ffCCCCCC"
             android:textColorHint="#ff808080"
             android:textSize="14sp" />
@@ -81,4 +81,4 @@
 
     </LinearLayout>
 
-</com.android.launcher3.Folder>
\ No newline at end of file
+</com.android.launcher3.Folder>
index 827332a..7ffebce 100644 (file)
         <attr name="indicatorSize" format="dimension" />
     </declare-styleable>
 
+    <attr name="layout_ignoreInsets" format="boolean" />
+    <attr name="layout_ignoreBottomInsets" format="boolean" />
+    <attr name="layout_ignoreTopInsets" format="boolean" />
+
     <declare-styleable name="InsettableFrameLayout_Layout">
-        <attr name="layout_ignoreInsets" format="boolean" />
+        <attr name="layout_ignoreInsets" />
+        <attr name="layout_ignoreTopInsets" />
+        <attr name="layout_ignoreBottomInsets" />
+    </declare-styleable>
+
+    <declare-styleable name="InsettableLinearLayout_Layout">
+        <attr name="layout_ignoreInsets" />
+        <attr name="layout_ignoreTopInsets" />
+        <attr name="layout_ignoreBottomInsets" />
     </declare-styleable>
 </resources>
index 3672179..e3c8194 100644 (file)
 <!-- Folders -->
     <!-- The amount that the preview contents are inset from the preview background -->
     <dimen name="folder_preview_padding">4dp</dimen>
+    <dimen name="folder_lock_margin">6dp</dimen>
+    <dimen name="folder_name_padding">10dp</dimen>
+    <dimen name="folder_lock_icon">48dp</dimen>
+
+    <!-- Folder icon dimens -->
+    <dimen name="folder_icon">64dp</dimen>
+    <dimen name="folder_icon_app_preview">22dp</dimen>
 
 <!-- Sizes for managed profile badges -->
     <dimen name="profile_badge_size">24dp</dimen>
     <dimen name="pending_widget_min_padding">8dp</dimen>
     <dimen name="pending_widget_elevation">2dp</dimen>
 
+<!-- Folder open animation -->
+    <integer name="folder_translate_y_dist">300</integer>
+    <integer name="folder_icon_translate_y_dist">100</integer>
+
 </resources>
index fefadef..b544788 100644 (file)
@@ -31,7 +31,7 @@
     <string name="receive_first_load_broadcast_permission" translatable="false">com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST</string>
 
     <!-- Application name -->
-    <string name="application_name">Launcher3</string>
+    <string name="app_name">Launcher3</string>
     <!-- Default folder name -->
     <string name="folder_name"></string>
     <!-- Work folder name -->
     <string name="permdesc_write_settings">Allows the app to change the settings and
         shortcuts in Home.</string>
 
+    <!-- Toast shown on clicking a direct call shortcut. [CHAR_LIMIT=80] -->
+    <string name="msg_no_phone_permission"><xliff:g id="app_name" example="Launcher3">%1$s</xliff:g> is not allowed to make phone calls</string>
+
     <!-- Widgets: -->
     <skip />    
 
index 7d60cbe..9104bc9 100644 (file)
@@ -49,7 +49,7 @@
 
     <style name="Icon.Folder">
         <item name="android:background">@null</item>
-        <item name="android:textColor">@color/quantum_panel_text_color</item>
+        <item name="android:textColor">@color/workspace_icon_text_color</item>
         <item name="android:shadowRadius">0</item>
         <item name="customShadows">false</item>
     </style>
index 84e2d49..a99d791 100644 (file)
@@ -504,13 +504,15 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
 
                 // Draw inner ring
                 d = FolderRingAnimator.sSharedInnerRingDrawable;
-                width = (int) (fra.getInnerRingSize() * getChildrenScale());
-                height = width;
-                canvas.save();
-                canvas.translate(centerX - width / 2, centerY - width / 2);
-                d.setBounds(0, 0, width, height);
-                d.draw(canvas);
-                canvas.restore();
+                if (d != null) {
+                    width = (int) (fra.getInnerRingSize() * getChildrenScale());
+                    height = width;
+                    canvas.save();
+                    canvas.translate(centerX - width / 2, centerY - width / 2);
+                    d.setBounds(0, 0, width, height);
+                    d.draw(canvas);
+                    canvas.restore();
+                }
             }
         }
 
index c1aa356..994d7d3 100644 (file)
@@ -25,11 +25,15 @@ import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.PowerManager;
+import android.provider.Settings;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
@@ -46,8 +50,10 @@ import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -89,6 +95,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
      */
     public static final int SCROLL_HINT_DURATION = DragController.SCROLL_DELAY;
 
+    private static final int CLOSE_FOLDER_DELAY_MS = 150;
+
+    private static final int ALPHA_DELAY_MULT = 15;
+
     /**
      * Fraction of icon width which behave as scroll region.
      */
@@ -96,6 +106,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
 
     private static final int FOLDER_NAME_ANIMATION_DURATION = 633;
 
+    private static final int REORDER_ANIMATION_DURATION = 230;
     private static final int REORDER_DELAY = 250;
     private static final int ON_EXIT_CLOSE_DELAY = 400;
     private static final Rect sTempRect = new Rect();
@@ -116,6 +127,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
 
     private final InputMethodManager mInputMethodManager;
 
+    private final PowerManager mPowerManager;
+
     protected final Launcher mLauncher;
     protected DragController mDragController;
     protected FolderInfo mInfo;
@@ -171,6 +184,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
         mInputMethodManager = (InputMethodManager)
                 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
 
+        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+
         Resources res = getResources();
         mExpandDuration = res.getInteger(R.integer.config_folderExpandDuration);
         mMaterialExpandDuration = res.getInteger(R.integer.config_materialFolderExpandDuration);
@@ -440,9 +455,41 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
         setScaleY(1f);
         setAlpha(1f);
         mState = STATE_SMALL;
+
+        View reveal = mLauncher.findViewById(R.id.reveal_fake_page_container);
+        reveal.setVisibility(View.VISIBLE);
+        View revealFolderIcon = mLauncher.findViewById(R.id.reveal_fake_folder_icon);
+        revealFolderIcon.setVisibility(View.INVISIBLE);
+    }
+
+    private void prepareFakeFolderIcon() {
+        mFolderIcon.buildDrawingCache(true);
+
+        Bitmap fakeFolderIcon = Bitmap.createBitmap(mFolderIcon.getDrawingCache());
+        View fakeFolderIconView = mLauncher.findViewById(R.id.reveal_fake_folder_icon);
+        FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams)
+                fakeFolderIconView.getLayoutParams();
+
+        // Get globalVisibleRect of the folderIcon. getWidth and getHeight are inaccurate for
+        // hotseat icons
+        Rect rect = new Rect();
+        mFolderIcon.getGlobalVisibleRect(rect);
+
+        flp.height = rect.height();
+        flp.width = rect.width();
+
+        fakeFolderIconView.setLayoutParams(flp);
+
+        int [] folderIconXY = new int[2];
+        mFolderIcon.getLocationOnScreen(folderIconXY);
+        fakeFolderIconView.setX(folderIconXY[0]);
+        fakeFolderIconView.setY(folderIconXY[1]);
+
+        fakeFolderIconView.setBackground(new BitmapDrawable(null, fakeFolderIcon));
+        fakeFolderIconView.setVisibility(View.INVISIBLE);
     }
 
-    public void animateOpen() {
+    public void animateOpen(Workspace workspace, int[] folderTouch) {
         if (!(getParent() instanceof DragLayer)) return;
 
         mContent.completePendingPageChanges();
@@ -473,7 +520,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
                 }
             };
         } else {
-            prepareReveal();
             centerAboutIcon();
 
             AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
@@ -490,7 +536,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
             Animator drift = ObjectAnimator.ofPropertyValuesHolder(this, tx, ty);
             drift.setDuration(mMaterialExpandDuration);
             drift.setStartDelay(mMaterialExpandStagger);
-            drift.setInterpolator(new LogDecelerateInterpolator(100, 0));
+            drift.setInterpolator(new LogDecelerateInterpolator(60, 0));
 
             int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
             int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
@@ -513,6 +559,34 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
             textAlpha.setStartDelay(mMaterialExpandStagger);
             textAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
 
+            prepareFakeFolderIcon();
+            float iconTransY = getResources().getInteger(R.integer.folder_icon_translate_y_dist);
+
+            final View fakeFolderIconView = mLauncher.findViewById(R.id.reveal_fake_folder_icon);
+            float baseIconTranslationY = fakeFolderIconView.getTranslationY();
+            PropertyValuesHolder iconty = PropertyValuesHolder.ofFloat("translationY",
+                    baseIconTranslationY, baseIconTranslationY + iconTransY);
+            PropertyValuesHolder iconAlpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f);
+
+            Animator fakeFolderIcon = LauncherAnimUtils.ofPropertyValuesHolder(fakeFolderIconView,
+                    iconty, iconAlpha);
+            fakeFolderIcon.setDuration(mMaterialExpandDuration);
+            fakeFolderIcon.setInterpolator(new AccelerateInterpolator(1.5f));
+            fakeFolderIcon.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mFolderIcon.setAlpha(0);
+                    fakeFolderIconView.setVisibility(View.VISIBLE);
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    fakeFolderIconView.setVisibility(View.INVISIBLE);
+                }
+            });
+
+            prepareReveal();
+
             anim.play(drift);
             anim.play(iconsAlpha);
             anim.play(textAlpha);
@@ -526,7 +600,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
                 @Override
                 public void run() {
                     mContentWrapper.setLayerType(LAYER_TYPE_NONE, null);
-                    mContentWrapper.setLayerType(LAYER_TYPE_NONE, null);
                 }
             };
         }
@@ -535,6 +608,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
             public void onAnimationStart(Animator animation) {
                 sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
                         mContent.getAccessibilityDescription());
+                hideWorkspace();
                 mState = STATE_ANIMATING;
             }
             @Override
@@ -628,31 +702,120 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
         }
     }
 
-    public void animateClosed() {
+    public int getState() {
+        return mState;
+    }
+
+    public void animateClosed(final boolean animate) {
         if (!(getParent() instanceof DragLayer)) return;
-        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0);
-        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 0.9f);
-        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 0.9f);
-        final ObjectAnimator oa =
-                LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
+        AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
 
-        oa.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                onCloseComplete();
-                setLayerType(LAYER_TYPE_NONE, null);
-                mState = STATE_SMALL;
-            }
+        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);
+        float transY = getResources().getInteger(R.integer.folder_translate_y_dist);
+        PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", 0f,
+                transY);
+
+        setLayerType(LAYER_TYPE_HARDWARE, null);
+
+        float animatorDurationScale = Settings.Global.getFloat(getContext().getContentResolver(),
+                Settings.Global.ANIMATOR_DURATION_SCALE, 1);
+        ObjectAnimator oa;
+        if (mPowerManager.isPowerSaveMode() || animatorDurationScale < 0.01f) {
+            // power save mode is no fun - skip alpha animation and just set it to 0
+            // otherwise the icons will stay around until the duration of the animation
+            oa = LauncherAnimUtils.ofPropertyValuesHolder(this, translationY);
+            setAlpha(0f);
+        } else {
+            oa = LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, translationY);
+        }
+
+        oa.setDuration(mMaterialExpandDuration);
+        oa.setInterpolator(new LogDecelerateInterpolator(60, 0));
+        anim.play(oa);
+
+        Animator reverseRevealAnim = null;
+        Animator fakeFolderIconAnim = null;
+
+        if (animate) {
+
+            prepareFakeFolderIcon();
+            float iconTransY = getResources().getInteger(R.integer.folder_icon_translate_y_dist);
+
+            final View fakeFolderIconView = mLauncher.findViewById(R.id.reveal_fake_folder_icon);
+            float baseIconTranslationY = fakeFolderIconView.getTranslationY();
+            PropertyValuesHolder iconty = PropertyValuesHolder.ofFloat("translationY",
+                    baseIconTranslationY + iconTransY, baseIconTranslationY);
+            PropertyValuesHolder iconAlpha = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
+
+            fakeFolderIconAnim = LauncherAnimUtils.ofPropertyValuesHolder(fakeFolderIconView,
+                    iconty, iconAlpha);
+            fakeFolderIconAnim.setDuration(mMaterialExpandDuration);
+            fakeFolderIconAnim.setInterpolator(new DecelerateInterpolator(2f));
+            fakeFolderIconAnim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mFolderIcon.setAlpha(0);
+                    fakeFolderIconView.setVisibility(View.VISIBLE);
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    fakeFolderIconView.setVisibility(View.INVISIBLE);
+                    mFolderIcon.setAlpha(1);
+
+                    View revealView = mLauncher.findViewById(R.id.reveal_fake_page_container);
+                    revealView.setVisibility(View.INVISIBLE);
+                }
+            });
+        } else {
+            View revealView = mLauncher.findViewById(R.id.reveal_fake_page_container);
+            revealView.setVisibility(View.INVISIBLE);
+            mFolderIcon.setAlpha(1);
+        }
+
+        if (reverseRevealAnim != null) {
+            anim.play(reverseRevealAnim);
+        }
+        if (fakeFolderIconAnim != null) {
+            anim.play(fakeFolderIconAnim);
+        }
+
+        anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
                 sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
                         getContext().getString(R.string.folder_closed));
+                unHideWorkspace();
                 mState = STATE_ANIMATING;
             }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                onCloseComplete();
+                setLayerType(LAYER_TYPE_NONE, null);
+                mState = STATE_SMALL;
+            }
         });
-        oa.setDuration(mExpandDuration);
-        setLayerType(LAYER_TYPE_HARDWARE, null);
-        oa.start();
+
+        anim.start();
+    }
+
+    private int mSavedWidgetsVisibilityState = INVISIBLE;
+    private void hideWorkspace() {
+        mSavedWidgetsVisibilityState = mLauncher.getWidgetsView().getVisibility();
+        mLauncher.getWidgetsView().setVisibility(INVISIBLE);
+        mLauncher.getWorkspace().setVisibility(INVISIBLE);
+        mLauncher.getHotseat().setVisibility(INVISIBLE);
+        mLauncher.getSearchDropTargetBar().setVisibility(INVISIBLE);
+        mLauncher.getPageIndicator().setVisibility(INVISIBLE);
+    }
+
+    private void unHideWorkspace() {
+        mLauncher.getWidgetsView().setVisibility(mSavedWidgetsVisibilityState);
+        mLauncher.getWorkspace().setVisibility(VISIBLE);
+        mLauncher.getHotseat().setVisibility(VISIBLE);
+        mLauncher.getSearchDropTargetBar().setVisibility(VISIBLE);
+        mLauncher.getPageIndicator().setVisibility(VISIBLE);
     }
 
     public boolean acceptDrop(DragObject d) {
@@ -966,22 +1129,22 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
         int centerY = (int) (sTempRect.top + sTempRect.height() * scale / 2);
         int centeredLeft = centerX - width / 2;
         int centeredTop = centerY - height / 2;
+        int currentPage = mLauncher.getWorkspace().getNextPage();
+
+        // We first fetch the currently visible CellLayoutChildren
+        CellLayout currentLayout = (CellLayout) mLauncher.getWorkspace().getChildAt(currentPage);
+        ShortcutAndWidgetContainer boundingLayout = currentLayout.getShortcutsAndWidgets();
+        Rect bounds = new Rect();
+        parent.getDescendantRectRelativeToSelf(boundingLayout, bounds);
 
-        // We need to bound the folder to the currently visible workspace area
-        mLauncher.getWorkspace().getPageAreaRelativeToDragLayer(sTempRect);
-        int left = Math.min(Math.max(sTempRect.left, centeredLeft),
-                sTempRect.left + sTempRect.width() - width);
-        int top = Math.min(Math.max(sTempRect.top, centeredTop),
-                sTempRect.top + sTempRect.height() - height);
-        if (grid.isPhone && (grid.availableWidthPx - width) < grid.iconSizePx) {
-            // Center the folder if it is full (on phones only)
-            left = (grid.availableWidthPx - width) / 2;
-        } else if (width >= sTempRect.width()) {
+        // Center the folder
+        int left = (grid.availableWidthPx - width) / 2;
+        // Drop the top down a little so it isn't bounded by the page indicators
+        int top = (int) (bounds.top + (bounds.height() * 1.15) - height);
+
+        if (width >= bounds.width()) {
             // If the folder doesn't fit within the bounds, center it about the desired bounds
-            left = sTempRect.left + (sTempRect.width() - width) / 2;
-        }
-        if (height >= sTempRect.height()) {
-            top = sTempRect.top + (sTempRect.height() - height) / 2;
+            left = bounds.left + (bounds.width() - width) / 2;
         }
 
         int folderPivotX = width / 2 + (centeredLeft - left);
index 8d534d2..85e3c33 100644 (file)
@@ -39,6 +39,7 @@ import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 import com.android.launcher3.DropTarget.DragObject;
@@ -60,17 +61,17 @@ public class FolderIcon extends FrameLayout implements FolderListener {
     private StylusEventHelper mStylusEventHelper;
 
     // The number of icons to display in the
-    public static final int NUM_ITEMS_IN_PREVIEW = 3;
+    public static final int NUM_ITEMS_IN_PREVIEW = 4;
     private static final int CONSUMPTION_ANIMATION_DURATION = 100;
     private static final int DROP_IN_ANIMATION_DURATION = 400;
     private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
     private static final int FINAL_ITEM_ANIMATION_DURATION = 200;
 
     // The degree to which the inner ring grows when accepting drop
-    private static final float INNER_RING_GROWTH_FACTOR = 0.15f;
+    private static final float INNER_RING_GROWTH_FACTOR = 0.0f;
 
     // The degree to which the outer ring is scaled in its natural state
-    private static final float OUTER_RING_GROWTH_FACTOR = 0.3f;
+    private static final float OUTER_RING_GROWTH_FACTOR = 0.1f;
 
     // The amount of vertical spread between items in the stack [0...1]
     private static final float PERSPECTIVE_SHIFT_FACTOR = 0.18f;
@@ -90,7 +91,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
 
     public static Drawable sSharedFolderLeaveBehind = null;
 
-    @Thunk ImageView mPreviewBackground;
+    @Thunk View mPreviewBackground;
     @Thunk BubbleTextView mFolderName;
 
     FolderRingAnimator mFolderRingAnimator = null;
@@ -161,11 +162,11 @@ public class FolderIcon extends FrameLayout implements FolderListener {
         lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
 
         // Offset the preview background to center this view accordingly
-        icon.mPreviewBackground = (ImageView) icon.findViewById(R.id.preview_background);
+        icon.mPreviewBackground = icon.findViewById(R.id.preview_background);
         lp = (FrameLayout.LayoutParams) icon.mPreviewBackground.getLayoutParams();
-        lp.topMargin = grid.folderBackgroundOffset;
-        lp.width = grid.folderIconSizePx;
-        lp.height = grid.folderIconSizePx;
+        lp.width = grid.iconSizePx;
+        lp.height = grid.iconSizePx;
+        icon.mPreviewBackground.setLayoutParams(lp);
 
         icon.setTag(folderInfo);
         icon.setOnClickListener(launcher);
@@ -183,6 +184,58 @@ public class FolderIcon extends FrameLayout implements FolderListener {
         folderInfo.addListener(icon);
 
         icon.setOnFocusChangeListener(launcher.mFocusHandler);
+        icon.setDrawingCacheEnabled(true);
+
+        // get dimen for the icon size
+        // padding is equal to 1/8 of icon size
+        // padding gets used at start and end accounting for 2/8
+        // small icons are separated by 1/2 padding
+        // Total padding equals 2.5/8 leaving 5.5/8 for icons
+        // 5.5/8 remaining, divided by 2 equals 2.75 for each small icon
+        int padding = grid.iconSizePx / 8;
+        int smallIconSize = (int) (padding * 2.75);
+
+        for (int i = NUM_ITEMS_IN_PREVIEW; i >= 0; i--) {
+            ImageView appIcon = null;
+            int marginLeft = 0, marginRight = 0, marginTop = 0, marginBottom = 0;
+            switch(i) {
+                case 0:
+                    appIcon = (ImageView) icon.findViewById(R.id.app_0);
+                    marginLeft = padding;
+                    marginTop = padding;
+                    break;
+                case 1:
+                    appIcon = (ImageView) icon.findViewById(R.id.app_1);
+                    marginTop = padding;
+                    marginRight = padding;
+                    break;
+                case 2:
+                    appIcon = (ImageView) icon.findViewById(R.id.app_2);
+                    marginBottom = padding;
+                    marginLeft = padding;
+                    break;
+                case 3:
+                    appIcon = (ImageView) icon.findViewById(R.id.app_3);
+                    marginBottom = padding;
+                    marginRight = padding;
+                    break;
+            }
+
+            if (appIcon != null) {
+                RelativeLayout.LayoutParams layoutParams
+                        = (RelativeLayout.LayoutParams) appIcon.getLayoutParams();
+
+                layoutParams.width = smallIconSize;
+                layoutParams.height = smallIconSize;
+                layoutParams.leftMargin = marginLeft;
+                layoutParams.rightMargin = marginRight;
+                layoutParams.topMargin = marginTop;
+                layoutParams.bottomMargin = marginBottom;
+
+                appIcon.setLayoutParams(layoutParams);
+            }
+        }
+
         return icon;
     }
 
@@ -220,11 +273,11 @@ public class FolderIcon extends FrameLayout implements FolderListener {
                 }
 
                 DeviceProfile grid = launcher.getDeviceProfile();
-                sPreviewSize = grid.folderIconSizePx;
+                sPreviewSize = grid.iconSizePx;
                 sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
-                sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer);
-                sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_nolip);
-                sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest);
+                sSharedOuterRingDrawable = res.getDrawable(R.drawable.folder_fill_highlight);
+                sSharedInnerRingDrawable = null;
+                sSharedFolderLeaveBehind = res.getDrawable(R.drawable.folder_bg);
                 sStaticValuesDirty = false;
             }
         }
@@ -375,7 +428,14 @@ public class FolderIcon extends FrameLayout implements FolderListener {
                 item = (ShortcutInfo) mDragInfo;
             }
             mFolder.beginExternalDrag(item);
-            mLauncher.openFolder(FolderIcon.this);
+            mFolderRingAnimator.mCellLayout.hideFolderAccept(mFolderRingAnimator);
+
+            int[] folderTouchXY = new int[2];
+            mFolder.getLocationOnScreen(folderTouchXY);
+            int[] folderTouchXYOffset = {folderTouchXY[0] + mFolder.getWidth() / 2,
+                    folderTouchXY[1] + mFolder.getHeight() / 2};
+
+            mLauncher.openFolder(FolderIcon.this, folderTouchXYOffset);
         }
     };
 
@@ -482,6 +542,15 @@ public class FolderIcon extends FrameLayout implements FolderListener {
         if (d.dragInfo instanceof AppInfo) {
             // Came from all apps -- make a copy
             item = ((AppInfo) d.dragInfo).makeShortcut();
+        } else if (d.dragInfo instanceof FolderInfo) {
+            FolderInfo folder = (FolderInfo) d.dragInfo;
+            mFolder.notifyDrop();
+            for (ShortcutInfo fItem : folder.contents) {
+                onDrop(fItem, d.dragView, null, 1.0f, mInfo.contents.size(), d.postAnimationRunnable, d);
+            }
+            mLauncher.removeFolder(folder);
+            LauncherModel.deleteItemFromDatabase(mLauncher, folder);
+            return;
         } else {
             item = (ShortcutInfo) d.dragInfo;
         }
@@ -511,7 +580,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
             mMaxPerspectiveShift = mBaselineIconSize * PERSPECTIVE_SHIFT_FACTOR;
 
             mPreviewOffsetX = (mTotalWidth - mAvailableSpaceInPreview) / 2;
-            mPreviewOffsetY = previewPadding + grid.folderBackgroundOffset;
+            mPreviewOffsetY = grid.folderBackgroundOffset;
         }
     }
 
@@ -622,13 +691,35 @@ public class FolderIcon extends FrameLayout implements FolderListener {
 
         int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
         if (!mAnimating) {
-            for (int i = nItemsInPreview - 1; i >= 0; i--) {
-                v = (TextView) items.get(i);
-                if (!mHiddenItems.contains(v.getTag())) {
-                    d = getTopDrawable(v);
-                    mParams = computePreviewItemDrawingParams(i, mParams);
-                    mParams.drawable = d;
-                    drawPreviewItem(canvas, mParams);
+            for (int i = NUM_ITEMS_IN_PREVIEW; i >= 0; i--) {
+                d = null;
+                if (i < items.size()) {
+                    v = (TextView) items.get(i);
+                    if (!mHiddenItems.contains(v.getTag())) {
+                        d = getTopDrawable(v);
+                        mParams = computePreviewItemDrawingParams(i, mParams);
+                        mParams.drawable = d;
+                    }
+                }
+
+                ImageView appIcon = null;
+                switch(i) {
+                    case 0:
+                        appIcon = (ImageView) findViewById(R.id.app_0);
+                        break;
+                    case 1:
+                        appIcon = (ImageView) findViewById(R.id.app_1);
+                        break;
+                    case 2:
+                        appIcon = (ImageView) findViewById(R.id.app_2);
+                        break;
+                    case 3:
+                        appIcon = (ImageView) findViewById(R.id.app_3);
+                        break;
+                }
+
+                if (appIcon != null) {
+                    appIcon.setImageDrawable(d);
                 }
             }
         } else {
@@ -645,10 +736,9 @@ public class FolderIcon extends FrameLayout implements FolderListener {
             final Runnable onCompleteRunnable) {
         final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
 
-        float iconSize = mLauncher.getDeviceProfile().iconSizePx;
-        final float scale0 = iconSize / d.getIntrinsicWidth() ;
-        final float transX0 = (mAvailableSpaceInPreview - iconSize) / 2;
-        final float transY0 = (mAvailableSpaceInPreview - iconSize) / 2 + getPaddingTop();
+        final float scale0 = 1.0f;
+        final float transX0 = (mAvailableSpaceInPreview - d.getIntrinsicWidth()) / 2;
+        final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2 + getPaddingTop();
         mAnimParams.drawable = d;
 
         ValueAnimator va = LauncherAnimUtils.ofFloat(this, 0f, 1.0f);
@@ -675,7 +765,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
             public void onAnimationEnd(Animator animation) {
                 mAnimating = false;
                 if (onCompleteRunnable != null) {
-                    onCompleteRunnable.run();
+                    mLauncher.runOnUiThread(onCompleteRunnable);
                 }
             }
         });
index aea21c9..32d752a 100644 (file)
@@ -103,7 +103,6 @@ public class FolderInfo extends ItemInfo {
         super.onAddToDatabase(context, values);
         values.put(LauncherSettings.Favorites.TITLE, title.toString());
         values.put(LauncherSettings.Favorites.OPTIONS, options);
-
     }
 
     void addListener(FolderListener listener) {
index 7343bf6..6400a0f 100644 (file)
@@ -24,10 +24,14 @@ public class InsettableFrameLayout extends FrameLayout implements
         if (child instanceof Insettable) {
             ((Insettable) child).setInsets(newInsets);
         } else if (!lp.ignoreInsets) {
-            lp.topMargin += (newInsets.top - oldInsets.top);
+            if (!lp.ignoreTopInsets) {
+                lp.topMargin += (newInsets.top - oldInsets.top);
+            }
             lp.leftMargin += (newInsets.left - oldInsets.left);
             lp.rightMargin += (newInsets.right - oldInsets.right);
-            lp.bottomMargin += (newInsets.bottom - oldInsets.bottom);
+            if (!lp.ignoreBottomInsets) {
+                lp.bottomMargin += (newInsets.bottom - oldInsets.bottom);
+            }
         }
         child.setLayoutParams(lp);
     }
@@ -65,6 +69,8 @@ public class InsettableFrameLayout extends FrameLayout implements
 
     public static class LayoutParams extends FrameLayout.LayoutParams {
         boolean ignoreInsets = false;
+        boolean ignoreTopInsets = false;
+        boolean ignoreBottomInsets = false;
 
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
@@ -72,6 +78,10 @@ public class InsettableFrameLayout extends FrameLayout implements
                     R.styleable.InsettableFrameLayout_Layout);
             ignoreInsets = a.getBoolean(
                     R.styleable.InsettableFrameLayout_Layout_layout_ignoreInsets, false);
+            ignoreTopInsets = a.getBoolean(
+                    R.styleable.InsettableFrameLayout_Layout_layout_ignoreTopInsets, false);
+            ignoreBottomInsets = a.getBoolean(
+                    R.styleable.InsettableFrameLayout_Layout_layout_ignoreBottomInsets, false);
             a.recycle();
         }
 
index 1f843cb..6faea20 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import android.Manifest;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -150,6 +151,8 @@ public class Launcher extends Activity
     private static final int REQUEST_BIND_APPWIDGET = 11;
     private static final int REQUEST_RECONFIGURE_APPWIDGET = 12;
 
+    private static final int REQUEST_PERMISSION_CALL_PHONE = 13;
+
     private static final int WORKSPACE_BACKGROUND_GRADIENT = 0;
     private static final int WORKSPACE_BACKGROUND_TRANSPARENT = 1;
     private static final int WORKSPACE_BACKGROUND_BLACK = 2;
@@ -867,6 +870,24 @@ public class Launcher extends Activity
     /** @Override for MNC */
     public void onRequestPermissionsResult(int requestCode, String[] permissions,
             int[] grantResults) {
+        if (requestCode == REQUEST_PERMISSION_CALL_PHONE && sPendingAddItem != null
+                && sPendingAddItem.requestCode == REQUEST_PERMISSION_CALL_PHONE) {
+            View v = null;
+            CellLayout layout = getCellLayout(sPendingAddItem.container, sPendingAddItem.screenId);
+            if (layout != null) {
+                v = layout.getChildAt(sPendingAddItem.cellX, sPendingAddItem.cellY);
+            }
+            Intent intent = sPendingAddItem.intent;
+            sPendingAddItem = null;
+            if (grantResults.length > 0
+                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                startActivity(v, intent, null);
+            } else {
+                // TODO: Show a snack bar with link to settings
+                Toast.makeText(this, getString(R.string.msg_no_phone_permission,
+                        getString(R.string.app_name)), Toast.LENGTH_SHORT).show();
+            }
+        }
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onRequestPermissionsResult(requestCode, permissions,
                     grantResults);
@@ -1821,6 +1842,10 @@ public class Launcher extends Activity
         return mHotseat;
     }
 
+    public View getPageIndicator() {
+        return mPageIndicators;
+    }
+
     public ViewGroup getOverviewPanel() {
         return mOverviewPanel;
     }
@@ -2688,6 +2713,11 @@ public class Launcher extends Activity
         final FolderInfo info = folderIcon.getFolderInfo();
         Folder openFolder = mWorkspace.getFolderForTag(info);
 
+        int[] folderTouchXY = new int[2];
+        v.getLocationOnScreen(folderTouchXY);
+        int[] folderTouchXYOffset = {folderTouchXY[0] + v.getWidth() / 2,
+                folderTouchXY[1] + v.getHeight() / 2};
+
         // If the folder info reports that the associated folder is open, then verify that
         // it is actually opened. There have been a few instances where this gets out of sync.
         if (info.opened && openFolder == null) {
@@ -2700,7 +2730,7 @@ public class Launcher extends Activity
             // Close any open folder
             closeFolder();
             // Open the requested folder
-            openFolder(folderIcon);
+            openFolder(folderIcon, folderTouchXYOffset);
         } else {
             // Find the open folder...
             int folderScreen;
@@ -2712,7 +2742,7 @@ public class Launcher extends Activity
                     // Close any folder open on the current screen
                     closeFolder();
                     // Pull the folder onto this screen
-                    openFolder(folderIcon);
+                    openFolder(folderIcon, folderTouchXYOffset);
                 }
             }
         }
@@ -2926,6 +2956,22 @@ public class Launcher extends Activity
             }
             return true;
         } catch (SecurityException e) {
+            if (Utilities.ATLEAST_MARSHMALLOW && tag instanceof ItemInfo) {
+                // Due to legacy reasons, direct call shortcuts require Launchers to have the
+                // corresponding permission. Show the appropriate permission prompt if that
+                // is the case.
+                if (intent.getComponent() == null
+                        && Intent.ACTION_CALL.equals(intent.getAction())
+                        && checkSelfPermission(Manifest.permission.CALL_PHONE) !=
+                            PackageManager.PERMISSION_GRANTED) {
+                    // TODO: Rename sPendingAddItem to a generic name.
+                    sPendingAddItem = preparePendingAddArgs(REQUEST_PERMISSION_CALL_PHONE, intent,
+                            0, (ItemInfo) tag);
+                    requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
+                            REQUEST_PERMISSION_CALL_PHONE);
+                    return false;
+                }
+            }
             Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
             Log.e(TAG, "Launcher does not have the permission to launch " + intent +
                     ". Make sure to create a MAIN intent-filter for the corresponding activity " +
@@ -3063,8 +3109,13 @@ public class Launcher extends Activity
      *
      * @param folderInfo The FolderInfo describing the folder to open.
      */
-    public void openFolder(FolderIcon folderIcon) {
+    public void openFolder(FolderIcon folderIcon, int[] folderTouch) {
         Folder folder = folderIcon.getFolder();
+
+        if (folder.getState() == Folder.STATE_ANIMATING) {
+            return;
+        }
+
         Folder openFolder = mWorkspace != null ? mWorkspace.getOpenFolder() : null;
         if (openFolder != null && openFolder != folder) {
             // Close any open folder before opening a folder.
@@ -3087,8 +3138,8 @@ public class Launcher extends Activity
             Log.w(TAG, "Opening folder (" + folder + ") which already has a parent (" +
                     folder.getParent() + ").");
         }
-        folder.animateOpen();
-        growAndFadeOutFolderIcon(folderIcon);
+        folder.animateOpen(getWorkspace(), folderTouch);
+        /*growAndFadeOutFolderIcon(folderIcon);*/
 
         // Notify the accessibility manager that this folder "window" has appeared and occluded
         // the workspace items
@@ -3107,17 +3158,21 @@ public class Launcher extends Activity
     }
 
     public void closeFolder(Folder folder) {
+        closeFolder(folder, true);
+    }
+
+    public void closeFolder(Folder folder, boolean animate) {
         folder.getInfo().opened = false;
 
         ViewGroup parent = (ViewGroup) folder.getParent().getParent();
         if (parent != null) {
             FolderIcon fi = (FolderIcon) mWorkspace.getViewForTag(folder.mInfo);
-            shrinkAndFadeInFolderIcon(fi);
+            /*shrinkAndFadeInFolderIcon(fi);*/
             if (fi != null) {
                 ((CellLayout.LayoutParams) fi.getLayoutParams()).canReorder = true;
             }
         }
-        folder.animateClosed();
+        folder.animateClosed(animate);
 
         // Notify the accessibility manager that this folder "window" has disappeard and no
         // longer occludeds the workspace items
index 8a5804f..5cde2e5 100644 (file)
@@ -40,7 +40,7 @@ public class LauncherSettings {
          * <P>Type: TEXT</P>
          */
         public static final String TITLE = "title";
-
+        
         /**
          * The Intent URL of the gesture, describing what it points to. This
          * value is given to {@link android.content.Intent#parseUri(String, int)} to create