Merge "Import translations. DO NOT MERGE" into ub-now-porkchop
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index 95b19ce..cb13291 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -997,11 +997,27 @@
return false;
}
+ private File getDefaultThumbFile() {
+ return new File(getFilesDir(), Build.VERSION.SDK_INT
+ + "_" + DEFAULT_WALLPAPER_THUMBNAIL_FILENAME);
+ }
+
+ private boolean saveDefaultWallpaperThumb(Bitmap b) {
+ // Delete old thumbnails.
+ new File(getFilesDir(), OLD_DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete();
+ new File(getFilesDir(), DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete();
+
+ for (int i = Build.VERSION_CODES.JELLY_BEAN; i < Build.VERSION.SDK_INT; i++) {
+ new File(getFilesDir(), i + "_" + DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete();
+ }
+ return writeImageToFileAsJpeg(getDefaultThumbFile(), b);
+ }
+
private ResourceWallpaperInfo getPreKKDefaultWallpaperInfo() {
Resources sysRes = Resources.getSystem();
int resId = sysRes.getIdentifier("default_wallpaper", "drawable", "android");
- File defaultThumbFile = new File(getFilesDir(), DEFAULT_WALLPAPER_THUMBNAIL_FILENAME);
+ File defaultThumbFile = getDefaultThumbFile();
Bitmap thumb = null;
boolean defaultWallpaperExists = false;
if (defaultThumbFile.exists()) {
@@ -1014,7 +1030,7 @@
thumb = createThumbnail(
defaultThumbSize, this, null, null, sysRes, resId, rotation, false);
if (thumb != null) {
- defaultWallpaperExists = writeImageToFileAsJpeg(defaultThumbFile, thumb);
+ defaultWallpaperExists = saveDefaultWallpaperThumb(thumb);
}
}
if (defaultWallpaperExists) {
@@ -1025,17 +1041,13 @@
@TargetApi(Build.VERSION_CODES.KITKAT)
private DefaultWallpaperInfo getDefaultWallpaper() {
- File defaultThumbFile = new File(getFilesDir(), DEFAULT_WALLPAPER_THUMBNAIL_FILENAME);
+ File defaultThumbFile = getDefaultThumbFile();
Bitmap thumb = null;
boolean defaultWallpaperExists = false;
if (defaultThumbFile.exists()) {
thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath());
defaultWallpaperExists = true;
} else {
- // Delete old thumbnail file, since we had a bug where the thumbnail wasn't being drawn
- // before
- new File(getFilesDir(), OLD_DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete();
-
Resources res = getResources();
Point defaultThumbSize = getDefaultThumbnailSize(res);
Drawable wallpaperDrawable = WallpaperManager.getInstance(this).getBuiltInDrawable(
@@ -1049,7 +1061,7 @@
c.setBitmap(null);
}
if (thumb != null) {
- defaultWallpaperExists = writeImageToFileAsJpeg(defaultThumbFile, thumb);
+ defaultWallpaperExists = saveDefaultWallpaperThumb(thumb);
}
}
if (defaultWallpaperExists) {
diff --git a/res/drawable-hdpi/focused_bg.9.png b/res/drawable-hdpi/focused_bg.9.png
deleted file mode 100644
index 2925ae8..0000000
--- a/res/drawable-hdpi/focused_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_pageindicator_add.png b/res/drawable-hdpi/ic_pageindicator_add.png
index 4bb8bfa..ab0e5db 100644
--- a/res/drawable-hdpi/ic_pageindicator_add.png
+++ b/res/drawable-hdpi/ic_pageindicator_add.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_pageindicator_current.png b/res/drawable-hdpi/ic_pageindicator_current.png
index bd15fb4..2e841f5 100644
--- a/res/drawable-hdpi/ic_pageindicator_current.png
+++ b/res/drawable-hdpi/ic_pageindicator_current.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_pageindicator_default.png b/res/drawable-hdpi/ic_pageindicator_default.png
index 2386cd8..07ab948 100644
--- a/res/drawable-hdpi/ic_pageindicator_default.png
+++ b/res/drawable-hdpi/ic_pageindicator_default.png
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_left.9.png b/res/drawable-hdpi/page_hover_left.9.png
new file mode 100644
index 0000000..5f7087c
--- /dev/null
+++ b/res/drawable-hdpi/page_hover_left.9.png
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_left_active.9.png b/res/drawable-hdpi/page_hover_left_active.9.png
new file mode 100644
index 0000000..8787126
--- /dev/null
+++ b/res/drawable-hdpi/page_hover_left_active.9.png
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_left_holo.9.png b/res/drawable-hdpi/page_hover_left_holo.9.png
deleted file mode 100644
index 8a1aa5f..0000000
--- a/res/drawable-hdpi/page_hover_left_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_right.9.png b/res/drawable-hdpi/page_hover_right.9.png
new file mode 100644
index 0000000..ef991b7
--- /dev/null
+++ b/res/drawable-hdpi/page_hover_right.9.png
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_right_active.9.png b/res/drawable-hdpi/page_hover_right_active.9.png
new file mode 100644
index 0000000..cd5b42d
--- /dev/null
+++ b/res/drawable-hdpi/page_hover_right_active.9.png
Binary files differ
diff --git a/res/drawable-hdpi/page_hover_right_holo.9.png b/res/drawable-hdpi/page_hover_right_holo.9.png
deleted file mode 100644
index abf8f51..0000000
--- a/res/drawable-hdpi/page_hover_right_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/quantum_panel.9.png b/res/drawable-hdpi/quantum_panel.9.png
index a005e0b..914961a 100644
--- a/res/drawable-hdpi/quantum_panel.9.png
+++ b/res/drawable-hdpi/quantum_panel.9.png
Binary files differ
diff --git a/res/drawable-hdpi/virtual_preload.9.png b/res/drawable-hdpi/virtual_preload.9.png
new file mode 100644
index 0000000..71e5326
--- /dev/null
+++ b/res/drawable-hdpi/virtual_preload.9.png
Binary files differ
diff --git a/res/drawable-hdpi/virtual_preload_folder.9.png b/res/drawable-hdpi/virtual_preload_folder.9.png
new file mode 100644
index 0000000..ece3226
--- /dev/null
+++ b/res/drawable-hdpi/virtual_preload_folder.9.png
Binary files differ
diff --git a/res/drawable-mdpi/focused_bg.9.png b/res/drawable-mdpi/focused_bg.9.png
deleted file mode 100644
index 89c29ac..0000000
--- a/res/drawable-mdpi/focused_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_pageindicator_add.png b/res/drawable-mdpi/ic_pageindicator_add.png
index e20ffa7..11659a3 100644
--- a/res/drawable-mdpi/ic_pageindicator_add.png
+++ b/res/drawable-mdpi/ic_pageindicator_add.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_pageindicator_current.png b/res/drawable-mdpi/ic_pageindicator_current.png
index bb49d31..08f43b4 100644
--- a/res/drawable-mdpi/ic_pageindicator_current.png
+++ b/res/drawable-mdpi/ic_pageindicator_current.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_pageindicator_default.png b/res/drawable-mdpi/ic_pageindicator_default.png
index 50d0989..635be4a 100644
--- a/res/drawable-mdpi/ic_pageindicator_default.png
+++ b/res/drawable-mdpi/ic_pageindicator_default.png
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_left.9.png b/res/drawable-mdpi/page_hover_left.9.png
new file mode 100644
index 0000000..0d537e6
--- /dev/null
+++ b/res/drawable-mdpi/page_hover_left.9.png
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_left_active.9.png b/res/drawable-mdpi/page_hover_left_active.9.png
new file mode 100644
index 0000000..3004f9e
--- /dev/null
+++ b/res/drawable-mdpi/page_hover_left_active.9.png
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_left_holo.9.png b/res/drawable-mdpi/page_hover_left_holo.9.png
deleted file mode 100644
index 561d3cd..0000000
--- a/res/drawable-mdpi/page_hover_left_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_right.9.png b/res/drawable-mdpi/page_hover_right.9.png
new file mode 100644
index 0000000..c0fbb7d
--- /dev/null
+++ b/res/drawable-mdpi/page_hover_right.9.png
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_right_active.9.png b/res/drawable-mdpi/page_hover_right_active.9.png
new file mode 100644
index 0000000..6d39687
--- /dev/null
+++ b/res/drawable-mdpi/page_hover_right_active.9.png
Binary files differ
diff --git a/res/drawable-mdpi/page_hover_right_holo.9.png b/res/drawable-mdpi/page_hover_right_holo.9.png
deleted file mode 100644
index 2681f23..0000000
--- a/res/drawable-mdpi/page_hover_right_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/quantum_panel.9.png b/res/drawable-mdpi/quantum_panel.9.png
index 785f573..b9b9506 100644
--- a/res/drawable-mdpi/quantum_panel.9.png
+++ b/res/drawable-mdpi/quantum_panel.9.png
Binary files differ
diff --git a/res/drawable-mdpi/virtual_preload.9.png b/res/drawable-mdpi/virtual_preload.9.png
new file mode 100644
index 0000000..a3c7519
--- /dev/null
+++ b/res/drawable-mdpi/virtual_preload.9.png
Binary files differ
diff --git a/res/drawable-mdpi/virtual_preload_folder.9.png b/res/drawable-mdpi/virtual_preload_folder.9.png
new file mode 100644
index 0000000..fa2f131
--- /dev/null
+++ b/res/drawable-mdpi/virtual_preload_folder.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/focused_bg.9.png b/res/drawable-xhdpi/focused_bg.9.png
deleted file mode 100644
index 197a269..0000000
--- a/res/drawable-xhdpi/focused_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pageindicator_add.png b/res/drawable-xhdpi/ic_pageindicator_add.png
index 9659e6f..af1da2d 100644
--- a/res/drawable-xhdpi/ic_pageindicator_add.png
+++ b/res/drawable-xhdpi/ic_pageindicator_add.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pageindicator_current.png b/res/drawable-xhdpi/ic_pageindicator_current.png
index 07b3137..0e9a52f 100644
--- a/res/drawable-xhdpi/ic_pageindicator_current.png
+++ b/res/drawable-xhdpi/ic_pageindicator_current.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pageindicator_default.png b/res/drawable-xhdpi/ic_pageindicator_default.png
index 0351d57..d0f14cd 100644
--- a/res/drawable-xhdpi/ic_pageindicator_default.png
+++ b/res/drawable-xhdpi/ic_pageindicator_default.png
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_left.9.png b/res/drawable-xhdpi/page_hover_left.9.png
new file mode 100644
index 0000000..9b0def8
--- /dev/null
+++ b/res/drawable-xhdpi/page_hover_left.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_left_active.9.png b/res/drawable-xhdpi/page_hover_left_active.9.png
new file mode 100644
index 0000000..6440bdf
--- /dev/null
+++ b/res/drawable-xhdpi/page_hover_left_active.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_left_holo.9.png b/res/drawable-xhdpi/page_hover_left_holo.9.png
deleted file mode 100644
index 4972a2e..0000000
--- a/res/drawable-xhdpi/page_hover_left_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_right.9.png b/res/drawable-xhdpi/page_hover_right.9.png
new file mode 100644
index 0000000..c7bdfe9
--- /dev/null
+++ b/res/drawable-xhdpi/page_hover_right.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_right_active.9.png b/res/drawable-xhdpi/page_hover_right_active.9.png
new file mode 100644
index 0000000..43660e5
--- /dev/null
+++ b/res/drawable-xhdpi/page_hover_right_active.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/page_hover_right_holo.9.png b/res/drawable-xhdpi/page_hover_right_holo.9.png
deleted file mode 100644
index b99461f..0000000
--- a/res/drawable-xhdpi/page_hover_right_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/quantum_panel.9.png b/res/drawable-xhdpi/quantum_panel.9.png
index 5726fd2..1bbb937 100644
--- a/res/drawable-xhdpi/quantum_panel.9.png
+++ b/res/drawable-xhdpi/quantum_panel.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/virtual_preload.9.png b/res/drawable-xhdpi/virtual_preload.9.png
new file mode 100644
index 0000000..d2c3fea
--- /dev/null
+++ b/res/drawable-xhdpi/virtual_preload.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/virtual_preload_folder.9.png b/res/drawable-xhdpi/virtual_preload_folder.9.png
new file mode 100644
index 0000000..1f9202b
--- /dev/null
+++ b/res/drawable-xhdpi/virtual_preload_folder.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/focused_bg.9.png b/res/drawable-xxhdpi/focused_bg.9.png
deleted file mode 100644
index 84d3062..0000000
--- a/res/drawable-xxhdpi/focused_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_pageindicator_add.png b/res/drawable-xxhdpi/ic_pageindicator_add.png
index 591b189..c288952 100644
--- a/res/drawable-xxhdpi/ic_pageindicator_add.png
+++ b/res/drawable-xxhdpi/ic_pageindicator_add.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_pageindicator_current.png b/res/drawable-xxhdpi/ic_pageindicator_current.png
index 4e4660f..b74e92e 100644
--- a/res/drawable-xxhdpi/ic_pageindicator_current.png
+++ b/res/drawable-xxhdpi/ic_pageindicator_current.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_pageindicator_default.png b/res/drawable-xxhdpi/ic_pageindicator_default.png
index 1cccb17..e362ece 100644
--- a/res/drawable-xxhdpi/ic_pageindicator_default.png
+++ b/res/drawable-xxhdpi/ic_pageindicator_default.png
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_left.9.png b/res/drawable-xxhdpi/page_hover_left.9.png
new file mode 100644
index 0000000..0c0eddd
--- /dev/null
+++ b/res/drawable-xxhdpi/page_hover_left.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_left_active.9.png b/res/drawable-xxhdpi/page_hover_left_active.9.png
new file mode 100644
index 0000000..a9ae222
--- /dev/null
+++ b/res/drawable-xxhdpi/page_hover_left_active.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_left_holo.9.png b/res/drawable-xxhdpi/page_hover_left_holo.9.png
deleted file mode 100644
index 626aafb..0000000
--- a/res/drawable-xxhdpi/page_hover_left_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_right.9.png b/res/drawable-xxhdpi/page_hover_right.9.png
new file mode 100644
index 0000000..d61f94f
--- /dev/null
+++ b/res/drawable-xxhdpi/page_hover_right.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_right_active.9.png b/res/drawable-xxhdpi/page_hover_right_active.9.png
new file mode 100644
index 0000000..079ee1e
--- /dev/null
+++ b/res/drawable-xxhdpi/page_hover_right_active.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/page_hover_right_holo.9.png b/res/drawable-xxhdpi/page_hover_right_holo.9.png
deleted file mode 100644
index 66257dc..0000000
--- a/res/drawable-xxhdpi/page_hover_right_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/quantum_panel.9.png b/res/drawable-xxhdpi/quantum_panel.9.png
index 035cdc4..4392aa0 100644
--- a/res/drawable-xxhdpi/quantum_panel.9.png
+++ b/res/drawable-xxhdpi/quantum_panel.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/virtual_preload.9.png b/res/drawable-xxhdpi/virtual_preload.9.png
index 0ec1740..93e3b33 100644
--- a/res/drawable-xxhdpi/virtual_preload.9.png
+++ b/res/drawable-xxhdpi/virtual_preload.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/virtual_preload_folder.9.png b/res/drawable-xxhdpi/virtual_preload_folder.9.png
index ee80c76..fae19b3 100644
--- a/res/drawable-xxhdpi/virtual_preload_folder.9.png
+++ b/res/drawable-xxhdpi/virtual_preload_folder.9.png
Binary files differ
diff --git a/res/drawable/focusable_view_bg.xml b/res/drawable/focusable_view_bg.xml
index 66661e2..e156513 100644
--- a/res/drawable/focusable_view_bg.xml
+++ b/res/drawable/focusable_view_bg.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+ Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,5 +16,11 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true" android:drawable="@drawable/focused_bg" />
-</selector>
+
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/focused_background" />
+ </shape>
+ </item>
+
+</selector>
\ No newline at end of file
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 7791609..0af9e59 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -30,6 +30,11 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
+ <com.android.launcher3.FocusIndicatorView
+ android:id="@+id/focus_indicator"
+ android:layout_width="52dp"
+ android:layout_height="52dp" />
+
<!-- The workspace contains 5 screens of cells -->
<com.android.launcher3.Workspace
android:id="@+id/workspace"
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 574b73e..46e0c0f 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -29,6 +29,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <com.android.launcher3.FocusIndicatorView
+ android:id="@+id/focus_indicator"
+ android:layout_width="52dp"
+ android:layout_height="52dp" />
+
<!-- The workspace contains 5 screens of cells -->
<com.android.launcher3.Workspace
android:id="@+id/workspace"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 685d03c..f8b8437 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -30,6 +30,11 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
+ <com.android.launcher3.FocusIndicatorView
+ android:id="@+id/focus_indicator"
+ android:layout_width="52dp"
+ android:layout_height="52dp" />
+
<!-- The workspace contains 5 screens of cells -->
<com.android.launcher3.Workspace
android:id="@+id/workspace"
diff --git a/res/layout/all_apps_button.xml b/res/layout/all_apps_button.xml
index 1b9ea08..9d6d82b 100644
--- a/res/layout/all_apps_button.xml
+++ b/res/layout/all_apps_button.xml
@@ -16,5 +16,4 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/WorkspaceIcon"
- android:focusable="true"
- android:background="@drawable/focusable_view_bg" />
+ android:focusable="true" />
diff --git a/res/layout/application.xml b/res/layout/application.xml
index e4909dd..c21dea0 100644
--- a/res/layout/application.xml
+++ b/res/layout/application.xml
@@ -16,5 +16,4 @@
<com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/WorkspaceIcon"
- android:focusable="true"
- android:background="@drawable/focusable_view_bg" />
+ android:focusable="true" />
diff --git a/res/layout/apps_customize_application.xml b/res/layout/apps_customize_application.xml
index b48b9b7..c56cdf3 100644
--- a/res/layout/apps_customize_application.xml
+++ b/res/layout/apps_customize_application.xml
@@ -14,11 +14,8 @@
limitations under the License.
-->
-<com.android.launcher3.PagedViewIcon
+<com.android.launcher3.BubbleTextView
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"
-
style="@style/WorkspaceIcon.AppsCustomize"
android:id="@+id/application_icon"
- android:focusable="true"
- android:background="@drawable/focusable_view_bg" />
+ android:focusable="true" />
diff --git a/res/layout/folder_application.xml b/res/layout/folder_application.xml
index 37dd79d..b48b613 100644
--- a/res/layout/folder_application.xml
+++ b/res/layout/folder_application.xml
@@ -16,5 +16,4 @@
<com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/WorkspaceIcon.Folder"
- android:focusable="true"
- android:background="@drawable/focusable_view_bg" />
+ android:focusable="true" />
diff --git a/res/layout/folder_icon.xml b/res/layout/folder_icon.xml
index 5147f99..fd45d76 100644
--- a/res/layout/folder_icon.xml
+++ b/res/layout/folder_icon.xml
@@ -19,8 +19,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:focusable="true"
- android:background="@drawable/focusable_view_bg">
+ android:focusable="true" >
<ImageView
android:id="@+id/preview_background"
android:layout_gravity="center_horizontal"
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 552e84c..0db60c9 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -106,7 +106,6 @@
<declare-styleable name="BubbleTextView">
<!-- A spacing override for the icons within a page -->
<attr name="customShadows" format="boolean" />
- <attr name="glowColor" format="color" />
</declare-styleable>
<!-- AppsCustomizePagedView specific attributes. These attributes are used to
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 4e64d41..8aa2184 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -24,6 +24,7 @@
<color name="info_target_hover_tint">#DA0099CC</color>
<color name="bubble_dark_background">#20000000</color>
+ <color name="focused_background">#80c6c5c5</color>
<color name="appwidget_error_color">#FCCC</color>
@@ -33,7 +34,6 @@
<color name="quantum_panel_text_color">#FF666666</color>
<color name="quantum_panel_text_shadow_color">#FFC4C4C4</color>
- <color name="folder_items_glow_color">#FFCCCCCC</color>
<color name="outline_color">#FFFFFFFF</color>
<color name="widget_text_panel">#FF374248</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 0da0b70..19ae44c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -79,7 +79,9 @@
<integer name="config_dropAnimMaxDuration">500</integer>
<!-- The duration of the UserFolder opening and closing animation -->
- <integer name="config_folderAnimDuration">120</integer>
+ <integer name="config_folderExpandDuration">120</integer>
+ <integer name="config_materialFolderExpandDuration">200</integer>
+ <integer name="config_materialFolderExpandStagger">60</integer>
<!-- The distance at which the animation should take the max duration -->
<integer name="config_dropAnimMaxDist">800</integer>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 893d7c0..b2e183c 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -101,4 +101,8 @@
<!-- The amount that the preview contents are inset from the preview background -->
<dimen name="folder_preview_padding">4dp</dimen>
<dimen name="folder_name_padding">10dp</dimen>
+
+<!-- Sizes for managed profile badges -->
+ <dimen name="profile_badge_size">24dp</dimen>
+ <dimen name="profile_badge_margin">4dp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index aa5f7b6..ff3509b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -243,6 +243,12 @@
<string name="workspace_cling_title">Organize your space</string>
<!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
<string name="workspace_cling_move_item">Touch & hold background to manage wallpaper, widgets and settings.</string>
+ <!-- The title text for workspace longpress action [CHAR_LIMIT=40] -->
+ <string name="workspace_cling_longpress_title">Wallpapers, widgets, & settings</string>
+ <!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
+ <string name="workspace_cling_longpress_description">Touch & hold background to customize</string>
+ <!-- The description of the button to dismiss the cling [CHAR_LIMIT=30] -->
+ <string name="workspace_cling_longpress_dismiss">GOT IT</string>
<!-- The title text for the Folder cling [CHAR_LIMIT=30] -->
<string name="folder_cling_title">Here\'s a folder</string>
<!-- The description of how to create a folder [CHAR_LIMIT=70] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 6079eee..0569306 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -91,7 +91,8 @@
<item name="android:shadowRadius">2.0</item>
<item name="android:shadowDx">0</item>
<item name="android:shadowDy">2</item>
- <item name="android:shadowColor">#FFC4C4C4</item>
+ <item name="android:shadowColor">@color/quantum_panel_text_shadow_color</item>
+ <item name="customShadows">false</item>
</style>
<style name="WorkspaceIcon.Folder">
@@ -103,7 +104,6 @@
<item name="android:shadowDy">2</item>
<item name="customShadows">false</item>
- <item name="glowColor">@color/folder_items_glow_color</item>
</style>
<style name="SearchDropTargetBar">
diff --git a/src/com/android/launcher3/AppsCustomizeCellLayout.java b/src/com/android/launcher3/AppsCustomizeCellLayout.java
index 3c8bda9..76b81d2 100644
--- a/src/com/android/launcher3/AppsCustomizeCellLayout.java
+++ b/src/com/android/launcher3/AppsCustomizeCellLayout.java
@@ -20,8 +20,16 @@
import android.view.View;
public class AppsCustomizeCellLayout extends CellLayout implements Page {
+
+ final FocusIndicatorView mFocusHandlerView;
+
public AppsCustomizeCellLayout(Context context) {
super(context);
+
+ mFocusHandlerView = new FocusIndicatorView(context);
+ addView(mFocusHandlerView, 0);
+ mFocusHandlerView.getLayoutParams().width = FocusIndicatorView.DEFAULT_LAYOUT_SIZE;
+ mFocusHandlerView.getLayoutParams().height = FocusIndicatorView.DEFAULT_LAYOUT_SIZE;
}
@Override
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index d23e65f..9f9c34b 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -28,7 +28,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -44,12 +43,12 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.Toast;
import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
import java.util.ArrayList;
import java.util.Collections;
@@ -144,8 +143,7 @@
*/
public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
View.OnClickListener, View.OnKeyListener, DragSource,
- PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
- LauncherTransitionable {
+ PagedViewWidget.ShortPressListener, LauncherTransitionable {
static final String TAG = "AppsCustomizePagedView";
private static Rect sTmpRect = new Rect();
@@ -167,7 +165,6 @@
// Save and Restore
private int mSaveInstanceStateItemIndex = -1;
- private PagedViewIcon mPressedIcon;
// Content
private ArrayList<AppInfo> mApps;
@@ -179,7 +176,6 @@
private int mClingFocusedY;
// Caching
- private Canvas mCanvas;
private IconCache mIconCache;
// Dimens
@@ -190,16 +186,6 @@
private int mNumWidgetPages;
private Rect mAllAppsPadding = new Rect();
- // Relating to the scroll and overscroll effects
- Workspace.ZInterpolator mZInterpolator = new Workspace.ZInterpolator(0.5f);
- private static float CAMERA_DISTANCE = 6500;
- private static float TRANSITION_SCALE_FACTOR = 0.74f;
- private static float TRANSITION_PIVOT = 0.65f;
- private static float TRANSITION_MAX_ROTATION = 22;
- private static final boolean PERFORM_OVERSCROLL_ROTATION = false;
- private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f);
- private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4);
-
// Previews & outlines
ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
private static final int sPageSleepDelay = 200;
@@ -237,13 +223,10 @@
mApps = new ArrayList<AppInfo>();
mWidgets = new ArrayList<Object>();
mIconCache = (LauncherAppState.getInstance()).getIconCache();
- mCanvas = new Canvas();
mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
// Save the default widget preview background
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
mClingFocusedX = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedX, 0);
@@ -404,7 +387,6 @@
if (!app.shouldShowAppOrWidgetProvider(widget.provider)) {
continue;
}
- widget.label = widget.label.trim();
if (widget.minWidth > 0 && widget.minHeight > 0) {
// Ensure that all widgets we show can be added on a workspace of this size
int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget);
@@ -454,39 +436,29 @@
@Override
public void onClick(View v) {
// When we have exited all apps or are in transition, disregard clicks
- if (!mLauncher.isAllAppsVisible() ||
- mLauncher.getWorkspace().isSwitchingState()) return;
+ if (!mLauncher.isAllAppsVisible()
+ || mLauncher.getWorkspace().isSwitchingState()
+ || !(v instanceof PagedViewWidget)) return;
- if (v instanceof PagedViewIcon) {
- // Animate some feedback to the click
- final AppInfo appInfo = (AppInfo) v.getTag();
-
- // Lock the drawable state to pressed until we return to Launcher
- if (mPressedIcon != null) {
- mPressedIcon.lockDrawableState();
- }
- mLauncher.onClickPagedViewIcon(v, appInfo);
- } else if (v instanceof PagedViewWidget) {
- // Let the user know that they have to long press to add a widget
- if (mWidgetInstructionToast != null) {
- mWidgetInstructionToast.cancel();
- }
- mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
- Toast.LENGTH_SHORT);
- mWidgetInstructionToast.show();
-
- // Create a little animation to show that the widget can move
- float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
- final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
- AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet();
- ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY);
- tyuAnim.setDuration(125);
- ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f);
- tydAnim.setDuration(100);
- bounce.play(tyuAnim).before(tydAnim);
- bounce.setInterpolator(new AccelerateInterpolator());
- bounce.start();
+ // Let the user know that they have to long press to add a widget
+ if (mWidgetInstructionToast != null) {
+ mWidgetInstructionToast.cancel();
}
+ mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
+ Toast.LENGTH_SHORT);
+ mWidgetInstructionToast.show();
+
+ // Create a little animation to show that the widget can move
+ float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
+ final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
+ AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet();
+ ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY);
+ tyuAnim.setDuration(125);
+ ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f);
+ tydAnim.setDuration(100);
+ bounce.play(tyuAnim).before(tydAnim);
+ bounce.setInterpolator(new AccelerateInterpolator());
+ bounce.start();
}
public boolean onKey(View v, int keyCode, KeyEvent event) {
@@ -502,7 +474,6 @@
}
private void beginDraggingApplication(View v) {
- mLauncher.getWorkspace().onDragStartedWithItem(v);
mLauncher.getWorkspace().beginDragShared(v, this);
}
@@ -544,18 +515,9 @@
@Override
public void run() {
mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
- // Options will be null for platforms with JB or lower, so this serves as an
- // SDK level check.
- if (options == null) {
- if (AppWidgetManager.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
- mWidgetLoadingId, info.componentName)) {
- mWidgetCleanupState = WIDGET_BOUND;
- }
- } else {
- if (AppWidgetManager.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
- mWidgetLoadingId, info.componentName, options)) {
- mWidgetCleanupState = WIDGET_BOUND;
- }
+ if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
+ mWidgetLoadingId, pInfo, options)) {
+ mWidgetCleanupState = WIDGET_BOUND;
}
}
};
@@ -683,9 +645,8 @@
int[] previewSizeBeforeScale = new int[1];
- preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.componentName,
- createWidgetInfo.previewImage, createWidgetInfo.icon, spanX, spanY,
- maxWidth, maxHeight, null, previewSizeBeforeScale);
+ preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
+ spanX, spanY, maxWidth, maxHeight, null, previewSizeBeforeScale);
// Compare the size of the drag preview to the preview in the AppsCustomize tray
int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
@@ -702,15 +663,7 @@
} else {
PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo);
- preview = Bitmap.createBitmap(icon.getIntrinsicWidth(),
- icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
-
- mCanvas.setBitmap(preview);
- mCanvas.save();
- WidgetPreviewLoader.renderDrawableToBitmap(icon, preview, 0, 0,
- icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
- mCanvas.restore();
- mCanvas.setBitmap(null);
+ preview = Utilities.createIconBitmap(icon, mLauncher);
createItemInfo.spanX = createItemInfo.spanY = 1;
}
@@ -736,7 +689,7 @@
protected boolean beginDragging(final View v) {
if (!super.beginDragging(v)) return false;
- if (v instanceof PagedViewIcon) {
+ if (v instanceof BubbleTextView) {
beginDraggingApplication(v);
} else if (v instanceof PagedViewWidget) {
if (!beginDraggingWidget(v)) {
@@ -751,9 +704,6 @@
public void run() {
// We don't enter spring-loaded mode if the drag has been cancelled
if (mLauncher.getDragController().isDragging()) {
- // Reset the alpha on the dragged icon before we drag
- resetDrawableState();
-
// Go into spring loaded mode (must happen before we startDrag())
mLauncher.enterSpringLoadedDragMode();
}
@@ -1002,13 +952,14 @@
ArrayList<Bitmap> images = new ArrayList<Bitmap>();
for (int i = startIndex; i < endIndex; ++i) {
AppInfo info = mApps.get(i);
- PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate(
+ BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
R.layout.apps_customize_application, layout, false);
- icon.applyFromApplicationInfo(info, true, this);
- icon.setOnClickListener(this);
+ icon.applyFromApplicationInfo(info);
+ icon.setOnClickListener(mLauncher);
icon.setOnLongClickListener(this);
icon.setOnTouchListener(this);
icon.setOnKeyListener(this);
+ icon.setOnFocusChangeListener(layout.mFocusHandlerView);
int index = i - startIndex;
int x = index % mCellCountX;
@@ -1365,73 +1316,7 @@
// In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
@Override
protected void screenScrolled(int screenCenter) {
- final boolean isRtl = isLayoutRtl();
super.screenScrolled(screenCenter);
-
- for (int i = 0; i < getChildCount(); i++) {
- View v = getPageAt(i);
- if (v != null) {
- float scrollProgress = getScrollProgress(screenCenter, v, i);
-
- float interpolatedProgress;
- float translationX;
- float maxScrollProgress = Math.max(0, scrollProgress);
- float minScrollProgress = Math.min(0, scrollProgress);
-
- if (isRtl) {
- translationX = maxScrollProgress * v.getMeasuredWidth();
- interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(maxScrollProgress));
- } else {
- translationX = minScrollProgress * v.getMeasuredWidth();
- interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(minScrollProgress));
- }
- float scale = (1 - interpolatedProgress) +
- interpolatedProgress * TRANSITION_SCALE_FACTOR;
-
- float alpha;
- if (isRtl && (scrollProgress > 0)) {
- alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(maxScrollProgress));
- } else if (!isRtl && (scrollProgress < 0)) {
- alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));
- } else {
- // On large screens we need to fade the page as it nears its leftmost position
- alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);
- }
-
- v.setCameraDistance(mDensity * CAMERA_DISTANCE);
- int pageWidth = v.getMeasuredWidth();
- int pageHeight = v.getMeasuredHeight();
-
- if (PERFORM_OVERSCROLL_ROTATION) {
- float xPivot = isRtl ? 1f - TRANSITION_PIVOT : TRANSITION_PIVOT;
- boolean isOverscrollingFirstPage = isRtl ? scrollProgress > 0 : scrollProgress < 0;
- boolean isOverscrollingLastPage = isRtl ? scrollProgress < 0 : scrollProgress > 0;
-
- if (i == 0 && isOverscrollingFirstPage) {
- // Overscroll to the left
- v.setPivotX(xPivot * pageWidth);
- v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
- scale = 1.0f;
- alpha = 1.0f;
- // On the first page, we don't want the page to have any lateral motion
- translationX = 0;
- } else if (i == getChildCount() - 1 && isOverscrollingLastPage) {
- // Overscroll to the right
- v.setPivotX((1 - xPivot) * pageWidth);
- v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
- scale = 1.0f;
- alpha = 1.0f;
- // On the last page, we don't want the page to have any lateral motion.
- translationX = 0;
- } else {
- v.setPivotY(pageHeight / 2.0f);
- v.setPivotX(pageWidth / 2.0f);
- v.setRotationY(0f);
- }
- }
- }
- }
-
enableHwLayersOnVisiblePages();
}
@@ -1476,7 +1361,7 @@
}
protected void overScroll(float amount) {
- acceleratedOverScroll(amount);
+ dampedOverScroll(amount);
}
/**
@@ -1634,23 +1519,6 @@
cancelAllTasks();
}
- @Override
- public void iconPressed(PagedViewIcon icon) {
- // Reset the previously pressed icon and store a reference to the pressed icon so that
- // we can reset it on return to Launcher (in Launcher.onResume())
- if (mPressedIcon != null) {
- mPressedIcon.resetDrawableState();
- }
- mPressedIcon = icon;
- }
-
- public void resetDrawableState() {
- if (mPressedIcon != null) {
- mPressedIcon.resetDrawableState();
- mPressedIcon = null;
- }
- }
-
/*
* We load an extra page on each side to prevent flashes from scrolling and loading of the
* widget previews in the background with the AsyncTasks.
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 5c2bb99..869b0ac 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -23,14 +23,13 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Rect;
import android.graphics.Region;
-import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.TextView;
@@ -44,12 +43,11 @@
private static SparseArray<Theme> sPreloaderThemes = new SparseArray<>(2);
- static final float SHADOW_LARGE_RADIUS = 4.0f;
- static final float SHADOW_SMALL_RADIUS = 1.75f;
- static final float SHADOW_Y_OFFSET = 2.0f;
- static final int SHADOW_LARGE_COLOUR = 0xDD000000;
- static final int SHADOW_SMALL_COLOUR = 0xCC000000;
- static final float PADDING_H = 8.0f;
+ private static final float SHADOW_LARGE_RADIUS = 4.0f;
+ private static final float SHADOW_SMALL_RADIUS = 1.75f;
+ private static final float SHADOW_Y_OFFSET = 2.0f;
+ private static final int SHADOW_LARGE_COLOUR = 0xDD000000;
+ private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
static final float PADDING_V = 3.0f;
private static final String TAG = "BubbleTextView";
@@ -57,14 +55,7 @@
private static final boolean DEBUG = false;
private HolographicOutlineHelper mOutlineHelper;
- private final Canvas mTempCanvas = new Canvas();
- private final Rect mTempRect = new Rect();
- private boolean mDidInvalidateForPressedState;
- private Bitmap mPressedOrFocusedBackground;
- private int mFocusedOutlineColor;
- private int mFocusedGlowColor;
- private int mPressedOutlineColor;
- private int mPressedGlowColor;
+ private Bitmap mPressedBackground;
private float mSlop;
@@ -72,14 +63,15 @@
private final boolean mCustomShadowsEnabled;
private boolean mIsTextVisible;
+ // TODO: Remove custom background handling code, as no instance of BubbleTextView use any
+ // background.
private boolean mBackgroundSizeChanged;
private final Drawable mBackground;
private boolean mStayPressed;
+ private boolean mIgnorePressedStateChange;
private CheckLongPressHelper mLongPressHelper;
- private CharSequence mDefaultText = "";
-
public BubbleTextView(Context context) {
this(context, null, 0);
}
@@ -91,11 +83,8 @@
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- Resources res = context.getResources();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
- setGlowColor(a.getColor(R.styleable.BubbleTextView_glowColor,
- res.getColor(R.color.outline_color)));
mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true);
a.recycle();
@@ -143,6 +132,7 @@
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
}
+ setText(info.title);
setTag(info);
if (info.wasPromise) {
@@ -150,6 +140,22 @@
}
}
+ 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);
+ setText(info.title);
+ if (info.contentDescription != null) {
+ setContentDescription(info.contentDescription);
+ }
+ setTag(info);
+ }
+
+
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
@@ -169,98 +175,22 @@
LauncherModel.checkItemInfo((ItemInfo) tag);
}
super.setTag(tag);
- if (tag instanceof ShortcutInfo) {
- final ShortcutInfo info = (ShortcutInfo) tag;
- mDefaultText = info.title;
- setText(mDefaultText);
- }
}
@Override
- protected void drawableStateChanged() {
- if (isPressed()) {
- // In this case, we have already created the pressed outline on ACTION_DOWN,
- // so we just need to do an invalidate to trigger draw
- if (!mDidInvalidateForPressedState) {
- setCellLayoutPressedOrFocusedIcon();
- }
- } else {
- // Otherwise, either clear the pressed/focused background, or create a background
- // for the focused state
- final boolean backgroundEmptyBefore = mPressedOrFocusedBackground == null;
- if (!mStayPressed) {
- mPressedOrFocusedBackground = null;
- }
- if (isFocused()) {
- if (getLayout() == null) {
- // In some cases, we get focus before we have been layed out. Set the
- // background to null so that it will get created when the view is drawn.
- mPressedOrFocusedBackground = null;
- } else {
- mPressedOrFocusedBackground = createGlowingOutline(
- mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor);
- }
- mStayPressed = false;
- setCellLayoutPressedOrFocusedIcon();
- }
- final boolean backgroundEmptyNow = mPressedOrFocusedBackground == null;
- if (!backgroundEmptyBefore && backgroundEmptyNow) {
- setCellLayoutPressedOrFocusedIcon();
- }
+ public void setPressed(boolean pressed) {
+ super.setPressed(pressed);
+
+ if (!mIgnorePressedStateChange) {
+ updateIconState();
}
+ }
- Drawable d = mBackground;
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
+ private void updateIconState() {
+ Drawable top = getCompoundDrawables()[1];
+ if (top instanceof FastBitmapDrawable) {
+ ((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed);
}
- super.drawableStateChanged();
- }
-
- /**
- * Draw this BubbleTextView into the given Canvas.
- *
- * @param destCanvas the canvas to draw on
- * @param padding the horizontal and vertical padding to use when drawing
- */
- private void drawWithPadding(Canvas destCanvas, int padding) {
- final Rect clipRect = mTempRect;
- getDrawingRect(clipRect);
-
- // adjust the clip rect so that we don't include the text label
- clipRect.bottom =
- getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + getLayout().getLineTop(0);
-
- // Draw the View into the bitmap.
- // The translate of scrollX and scrollY is necessary when drawing TextViews, because
- // they set scrollX and scrollY to large values to achieve centered text
- destCanvas.save();
- destCanvas.scale(getScaleX(), getScaleY(),
- (getWidth() + padding) / 2, (getHeight() + padding) / 2);
- destCanvas.translate(-getScrollX() + padding / 2, -getScrollY() + padding / 2);
- destCanvas.clipRect(clipRect, Op.REPLACE);
- draw(destCanvas);
- destCanvas.restore();
- }
-
- public void setGlowColor(int color) {
- mFocusedOutlineColor = mFocusedGlowColor = mPressedOutlineColor = mPressedGlowColor = color;
- }
-
- /**
- * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
- * Responsibility for the bitmap is transferred to the caller.
- */
- private Bitmap createGlowingOutline(Canvas canvas, int outlineColor, int glowColor) {
- final int padding = mOutlineHelper.mMaxOuterBlurRadius;
- final Bitmap b = Bitmap.createBitmap(
- getWidth() + padding, getHeight() + padding, Bitmap.Config.ARGB_8888);
-
- canvas.setBitmap(b);
- drawWithPadding(canvas, padding);
- mOutlineHelper.applyExtraThickExpensiveOutlineWithBlur(b, canvas, glowColor, outlineColor);
- canvas.setBitmap(null);
-
- return b;
}
@Override
@@ -271,20 +201,11 @@
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
- // So that the pressed outline is visible immediately when isPressed() is true,
+ // So that the pressed outline is visible immediately on setStayPressed(),
// we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time
// to create it)
- if (mPressedOrFocusedBackground == null) {
- mPressedOrFocusedBackground = createGlowingOutline(
- mTempCanvas, mPressedGlowColor, mPressedOutlineColor);
- }
- // Invalidate so the pressed state is visible, or set a flag so we know that we
- // have to call invalidate as soon as the state is "pressed"
- if (isPressed()) {
- mDidInvalidateForPressedState = true;
- setCellLayoutPressedOrFocusedIcon();
- } else {
- mDidInvalidateForPressedState = false;
+ if (mPressedBackground == null) {
+ mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
}
mLongPressHelper.postCheckForLongPress();
@@ -294,7 +215,7 @@
// If we've touched down and up on an item, and it's still not "pressed", then
// destroy the pressed outline
if (!isPressed()) {
- mPressedOrFocusedBackground = null;
+ mPressedBackground = null;
}
mLongPressHelper.cancelLongPress();
@@ -311,34 +232,47 @@
void setStayPressed(boolean stayPressed) {
mStayPressed = stayPressed;
if (!stayPressed) {
- mPressedOrFocusedBackground = null;
+ mPressedBackground = null;
}
- setCellLayoutPressedOrFocusedIcon();
+
+ // Only show the shadow effect when persistent pressed state is set.
+ if (getParent() instanceof ShortcutAndWidgetContainer) {
+ CellLayout layout = (CellLayout) getParent().getParent();
+ layout.setPressedIcon(this, mPressedBackground, mOutlineHelper.shadowBitmapPadding);
+ }
+
+ updateIconState();
}
- void setCellLayoutPressedOrFocusedIcon() {
- // Disable pressed state when the icon is in preloader state.
- if ((getParent() instanceof ShortcutAndWidgetContainer) &&
- !(getCompoundDrawables()[1] instanceof PreloadIconDrawable)){
- ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) getParent();
- if (parent != null) {
- CellLayout layout = (CellLayout) parent.getParent();
- layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null);
+ void clearPressedBackground() {
+ setPressed(false);
+ setStayPressed(false);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (super.onKeyDown(keyCode, event)) {
+ // Pre-create shadow so show immediately on click.
+ if (mPressedBackground == null) {
+ mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
}
+ return true;
}
+ return false;
}
- void clearPressedOrFocusedBackground() {
- mPressedOrFocusedBackground = null;
- setCellLayoutPressedOrFocusedIcon();
- }
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ // Unlike touch events, keypress event propagate pressed state change immediately,
+ // without waiting for onClickHandler to execute. Disable pressed state changes here
+ // to avoid flickering.
+ mIgnorePressedStateChange = true;
+ boolean result = super.onKeyUp(keyCode, event);
- Bitmap getPressedOrFocusedBackground() {
- return mPressedOrFocusedBackground;
- }
-
- int getPressedOrFocusedBackgroundPadding() {
- return mOutlineHelper.mMaxOuterBlurRadius / 2;
+ mPressedBackground = null;
+ mIgnorePressedStateChange = false;
+ updateIconState();
+ return result;
}
@Override
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 1073764..d0b3f43 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -71,8 +71,8 @@
private int mWidthGap;
private int mHeightGap;
private int mMaxGap;
- private boolean mScrollingTransformsDirty = false;
private boolean mDropPending = false;
+ private boolean mIsDragTarget = true;
// These are temporary variables to prevent having to allocate a new object just to
// return an (x, y) value from helper functions. Do NOT use them to maintain other state.
@@ -123,7 +123,7 @@
private int mDragOutlineCurrent = 0;
private final Paint mDragOutlinePaint = new Paint();
- private BubbleTextView mPressedOrFocusedIcon;
+ private final FastBitmapView mTouchFeedbackView;
private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
HashMap<CellLayout.LayoutParams, Animator>();
@@ -288,6 +288,9 @@
mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap,
mCountX, mCountY);
+ mTouchFeedbackView = new FastBitmapView(context);
+ // Make the feedback view large enough to hold the blur bitmap.
+ addView(mTouchFeedbackView, (int) (grid.cellWidthPx * 1.5), (int) (grid.cellHeightPx * 1.5));
addView(mShortcutsAndWidgets);
}
@@ -334,14 +337,6 @@
return mDropPending;
}
- private void invalidateBubbleTextView(BubbleTextView icon) {
- final int padding = icon.getPressedOrFocusedBackgroundPadding();
- invalidate(icon.getLeft() + getPaddingLeft() - padding,
- icon.getTop() + getPaddingTop() - padding,
- icon.getRight() + getPaddingLeft() + padding,
- icon.getBottom() + getPaddingTop() + padding);
- }
-
void setOverScrollAmount(float r, boolean left) {
if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
mOverScrollForegroundDrawable = mOverScrollLeft;
@@ -355,24 +350,23 @@
invalidate();
}
- void setPressedOrFocusedIcon(BubbleTextView icon) {
- // We draw the pressed or focused BubbleTextView's background in CellLayout because it
- // requires an expanded clip rect (due to the glow's blur radius)
- BubbleTextView oldIcon = mPressedOrFocusedIcon;
- mPressedOrFocusedIcon = icon;
- if (oldIcon != null) {
- invalidateBubbleTextView(oldIcon);
- }
- if (mPressedOrFocusedIcon != null) {
- invalidateBubbleTextView(mPressedOrFocusedIcon);
- }
- }
-
- void setIsDragOverlapping(boolean isDragOverlapping) {
- if (mIsDragOverlapping != isDragOverlapping) {
- mIsDragOverlapping = isDragOverlapping;
- setUseActiveGlowBackground(mIsDragOverlapping);
- invalidate();
+ void setPressedIcon(BubbleTextView icon, Bitmap background, int padding) {
+ if (icon == null || background == null) {
+ mTouchFeedbackView.setBitmap(null);
+ mTouchFeedbackView.animate().cancel();
+ } else {
+ int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight()
+ - (mCountX * mCellWidth);
+ mTouchFeedbackView.setTranslationX(icon.getLeft() + (int) Math.ceil(offset / 2f)
+ - padding);
+ mTouchFeedbackView.setTranslationY(icon.getTop() - padding);
+ if (mTouchFeedbackView.setBitmap(background)) {
+ mTouchFeedbackView.setAlpha(0);
+ mTouchFeedbackView.animate().alpha(1)
+ .setDuration(FastBitmapDrawable.CLICK_FEEDBACK_DURATION)
+ .setInterpolator(FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR)
+ .start();
+ }
}
}
@@ -384,27 +378,26 @@
mDrawBackground = false;
}
+ void disableDragTarget() {
+ mIsDragTarget = false;
+ }
+
+ boolean isDragTarget() {
+ return mIsDragTarget;
+ }
+
+ void setIsDragOverlapping(boolean isDragOverlapping) {
+ if (mIsDragOverlapping != isDragOverlapping) {
+ mIsDragOverlapping = isDragOverlapping;
+ setUseActiveGlowBackground(mIsDragOverlapping);
+ invalidate();
+ }
+ }
+
boolean getIsDragOverlapping() {
return mIsDragOverlapping;
}
- protected void setOverscrollTransformsDirty(boolean dirty) {
- mScrollingTransformsDirty = dirty;
- }
-
- protected void resetOverscrollTransforms() {
- if (mScrollingTransformsDirty) {
- setOverscrollTransformsDirty(false);
- setTranslationX(0);
- setRotationY(0);
- // It doesn't matter if we pass true or false here, the important thing is that we
- // pass 0, which results in the overscroll drawable not being drawn any more.
- setOverScrollAmount(0, false);
- setPivotX(getMeasuredWidth() / 2);
- setPivotY(getMeasuredHeight() / 2);
- }
- }
-
@Override
protected void onDraw(Canvas canvas) {
// When we're large, we are either drawn in a "hover" state (ie when dragging an item to
@@ -440,23 +433,6 @@
}
}
- // We draw the pressed or focused BubbleTextView's background in CellLayout because it
- // requires an expanded clip rect (due to the glow's blur radius)
- if (mPressedOrFocusedIcon != null) {
- final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
- final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
- if (b != null) {
- int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() -
- (mCountX * mCellWidth);
- int left = getPaddingLeft() + (int) Math.ceil(offset / 2f);
- int top = getPaddingTop();
- canvas.drawBitmap(b,
- mPressedOrFocusedIcon.getLeft() + left - padding,
- mPressedOrFocusedIcon.getTop() + top - padding,
- null);
- }
- }
-
if (DEBUG_VISUALIZE_OCCUPIED) {
int[] pt = new int[2];
ColorDrawable cd = new ColorDrawable(Color.RED);
@@ -964,6 +940,7 @@
}
public void setBackgroundAlphaMultiplier(float multiplier) {
+
if (mBackgroundAlphaMultiplier != multiplier) {
mBackgroundAlphaMultiplier = multiplier;
invalidate();
@@ -989,10 +966,7 @@
}
public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
- if (getChildCount() > 0) {
- return (ShortcutAndWidgetContainer) getChildAt(0);
- }
- return null;
+ return mShortcutsAndWidgets;
}
public View getChildAt(int x, int y) {
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index 80f8dfc..72d33dae 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -96,8 +96,10 @@
setOnHierarchyChangeListener(this);
final Resources res = getResources();
- mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left_holo);
- mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right_holo);
+ mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left);
+ mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right);
+ mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
+ mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
mBackground = res.getDrawable(R.drawable.apps_customize_bg);
}
@@ -850,8 +852,11 @@
}
private boolean mInScrollArea;
+ private boolean mShowPageHints;
private Drawable mLeftHoverDrawable;
private Drawable mRightHoverDrawable;
+ private Drawable mLeftHoverDrawableActive;
+ private Drawable mRightHoverDrawableActive;
void onEnterScrollArea(int direction) {
mInScrollArea = true;
@@ -863,6 +868,16 @@
invalidate();
}
+ void showPageHints() {
+ mShowPageHints = true;
+ invalidate();
+ }
+
+ void hidePageHints() {
+ mShowPageHints = false;
+ invalidate();
+ }
+
/**
* Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
*/
@@ -883,25 +898,32 @@
super.dispatchDraw(canvas);
// Draw screen hover indicators above children.
- if (mInScrollArea && !LauncherAppState.getInstance().isScreenLarge()) {
+ if (mShowPageHints) {
Workspace workspace = mLauncher.getWorkspace();
int width = getMeasuredWidth();
Rect childRect = new Rect();
- getDescendantRectRelativeToSelf(workspace.getChildAt(0), childRect);
+ getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.getChildCount() - 1),
+ childRect);
int page = workspace.getNextPage();
final boolean isRtl = isLayoutRtl();
CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1);
CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1);
- if (leftPage != null && leftPage.getIsDragOverlapping()) {
- mLeftHoverDrawable.setBounds(0, childRect.top,
- mLeftHoverDrawable.getIntrinsicWidth(), childRect.bottom);
- mLeftHoverDrawable.draw(canvas);
- } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
- mRightHoverDrawable.setBounds(width - mRightHoverDrawable.getIntrinsicWidth(),
+ if (leftPage != null && leftPage.isDragTarget()) {
+ Drawable left = mInScrollArea && leftPage.getIsDragOverlapping() ?
+ mLeftHoverDrawableActive : mLeftHoverDrawable;
+ left.setBounds(0, childRect.top,
+ left.getIntrinsicWidth(), childRect.bottom);
+ left.draw(canvas);
+ }
+ if (rightPage != null && rightPage.isDragTarget()) {
+ Drawable right = mInScrollArea && rightPage.getIsDragOverlapping() ?
+ mRightHoverDrawableActive : mRightHoverDrawable;
+
+ right.setBounds(width - right.getIntrinsicWidth(),
childRect.top, width, childRect.bottom);
- mRightHoverDrawable.draw(canvas);
+ right.draw(canvas);
}
}
}
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index cf7c22e..7c9e77e 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -16,30 +16,62 @@
package com.android.launcher3;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.util.SparseArray;
class FastBitmapDrawable extends Drawable {
+ static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() {
+
+ @Override
+ public float getInterpolation(float input) {
+ if (input < 0.05f) {
+ return input / 0.05f;
+ } else if (input < 0.3f){
+ return 1;
+ } else {
+ return (1 - input) / 0.7f;
+ }
+ }
+ };
+ static final long CLICK_FEEDBACK_DURATION = 2000;
+
+ private static final int PRESSED_BRIGHTNESS = 100;
private static ColorMatrix sGhostModeMatrix;
private static final ColorMatrix sTempMatrix = new ColorMatrix();
+ /**
+ * Store the brightness colors filters to optimize animations during icon press. This
+ * only works for non-ghost-mode icons.
+ */
+ private static final SparseArray<ColorFilter> sCachedBrightnessFilter =
+ new SparseArray<ColorFilter>();
+
private static final int GHOST_MODE_MIN_COLOR_RANGE = 130;
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
- private Bitmap mBitmap;
+ private final Bitmap mBitmap;
private int mAlpha;
private int mBrightness = 0;
private boolean mGhostModeEnabled = false;
+ private boolean mPressed = false;
+ private ObjectAnimator mPressedAnimator;
+
FastBitmapDrawable(Bitmap b) {
mAlpha = 255;
mBitmap = b;
@@ -114,6 +146,23 @@
}
}
+ public void setPressed(boolean pressed) {
+ if (mPressed != pressed) {
+ mPressed = pressed;
+ if (mPressed) {
+ mPressedAnimator = ObjectAnimator
+ .ofInt(this, "brightness", PRESSED_BRIGHTNESS)
+ .setDuration(CLICK_FEEDBACK_DURATION);
+ mPressedAnimator.setInterpolator(CLICK_FEEDBACK_INTERPOLATOR);
+ mPressedAnimator.start();
+ } else if (mPressedAnimator != null) {
+ mPressedAnimator.cancel();
+ setBrightness(0);
+ }
+ }
+ invalidateSelf();
+ }
+
public boolean isGhostModeEnabled() {
return mGhostModeEnabled;
}
@@ -122,14 +171,11 @@
return mBrightness;
}
- public void addBrightness(int amount) {
- setBrightness(mBrightness + amount);
- }
-
public void setBrightness(int brightness) {
if (mBrightness != brightness) {
mBrightness = brightness;
updateFilter();
+ invalidateSelf();
}
}
@@ -157,8 +203,13 @@
mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix));
}
} else if (mBrightness != 0) {
- setBrightnessMatrix(sTempMatrix, mBrightness);
- mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix));
+ ColorFilter filter = sCachedBrightnessFilter.get(mBrightness);
+ if (filter == null) {
+ filter = new PorterDuffColorFilter(Color.argb(mBrightness, 255, 255, 255),
+ PorterDuff.Mode.SRC_ATOP);
+ sCachedBrightnessFilter.put(mBrightness, filter);
+ }
+ mPaint.setColorFilter(filter);
} else {
mPaint.setColorFilter(null);
}
diff --git a/src/com/android/launcher3/FastBitmapView.java b/src/com/android/launcher3/FastBitmapView.java
new file mode 100644
index 0000000..0937eb7
--- /dev/null
+++ b/src/com/android/launcher3/FastBitmapView.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.view.View;
+
+public class FastBitmapView extends View {
+
+ private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+ private Bitmap mBitmap;
+
+ public FastBitmapView(Context context) {
+ super(context);
+ }
+
+ /**
+ * Applies the new bitmap.
+ * @return true if the view was invalidated.
+ */
+ public boolean setBitmap(Bitmap b) {
+ if (b != mBitmap){
+ if (mBitmap != null) {
+ invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+ }
+ mBitmap = b;
+ if (mBitmap != null) {
+ invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mBitmap != null) {
+ canvas.drawBitmap(mBitmap, 0, 0, mPaint);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index df5e0fc..34e752b 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -22,8 +22,6 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ScrollView;
-import android.widget.TabHost;
-import android.widget.TabWidget;
import java.util.ArrayList;
import java.util.Collections;
@@ -89,7 +87,6 @@
final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent();
final PagedView container = (PagedView) parent.getParent();
- final AppsCustomizeTabHost tabHost = findTabHostParent(container);
final int widgetIndex = parent.indexOfChild(w);
final int widgetCount = parent.getChildCount();
final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parent));
@@ -228,6 +225,13 @@
* Handles key events in a PageViewCellLayout containing PagedViewIcons.
*/
static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) {
+ final int action = e.getAction();
+ if (((action == KeyEvent.ACTION_DOWN) && v.onKeyDown(keyCode, e))
+ || ((action == KeyEvent.ACTION_UP) && v.onKeyUp(keyCode, e))) {
+ // Let the view handle the confirmation key.
+ return true;
+ }
+
ViewGroup parentLayout;
ViewGroup itemContainer;
int countX;
@@ -246,7 +250,6 @@
// Note we have an extra parent because of the
// PagedViewCellLayout/PagedViewCellLayoutChildren relationship
final PagedView container = (PagedView) parentLayout.getParent();
- final AppsCustomizeTabHost tabHost = findTabHostParent(container);
final int iconIndex = itemContainer.indexOfChild(v);
final int itemCount = itemContainer.getChildCount();
final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout));
@@ -255,7 +258,6 @@
final int x = iconIndex % countX;
final int y = iconIndex / countX;
- final int action = e.getAction();
final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
ViewGroup newParent = null;
// Side pages do not always load synchronously, so check before focusing child siblings
@@ -319,15 +321,6 @@
}
wasHandled = true;
break;
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- if (handleKeyEvent) {
- // Simulate a click on the icon
- View.OnClickListener clickListener = (View.OnClickListener) container;
- clickListener.onClick(v);
- }
- wasHandled = true;
- break;
case KeyEvent.KEYCODE_PAGE_UP:
if (handleKeyEvent) {
// Select the first icon on the previous page, or the first icon on this page
diff --git a/src/com/android/launcher3/FocusIndicatorView.java b/src/com/android/launcher3/FocusIndicatorView.java
new file mode 100644
index 0000000..12b7a40
--- /dev/null
+++ b/src/com/android/launcher3/FocusIndicatorView.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewParent;
+
+public class FocusIndicatorView extends View implements View.OnFocusChangeListener {
+
+ // It can be any number >0. The view is resized using scaleX and scaleY.
+ static final int DEFAULT_LAYOUT_SIZE = 100;
+ private static final float MIN_VISIBLE_ALPHA = 0.2f;
+
+ private static final int[] sTempPos = new int[2];
+ private static final int[] sTempShift = new int[2];
+
+ private final int[] mIndicatorPos = new int[2];
+ private final int[] mTargetViewPos = new int[2];
+
+ private View mLastFocusedView;
+ private boolean mInitiated;
+
+ private Pair<View, Boolean> mPendingCall;
+
+ public FocusIndicatorView(Context context) {
+ this(context, null);
+ }
+
+ public FocusIndicatorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setAlpha(0);
+ setBackgroundColor(getResources().getColor(R.color.focused_background));
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ // Redraw if it is already showing. This avoids a bug where the height changes by a small
+ // amount on connecting/disconnecting a bluetooth keyboard.
+ if (mLastFocusedView != null) {
+ mPendingCall = Pair.create(mLastFocusedView, Boolean.TRUE);
+ invalidate();
+ }
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ mPendingCall = null;
+ if (!mInitiated && (getWidth() == 0)) {
+ // View not yet laid out. Wait until the view is ready to be drawn, so that be can
+ // get the location on screen.
+ mPendingCall = Pair.create(v, hasFocus);
+ invalidate();
+ return;
+ }
+
+ if (!mInitiated) {
+ getLocationRelativeToParentPagedView(this, mIndicatorPos);
+ mInitiated = true;
+ }
+
+ if (hasFocus) {
+ int indicatorWidth = getWidth();
+ int indicatorHeight = getHeight();
+
+ float scaleX = v.getScaleX() * v.getWidth() / indicatorWidth;
+ float scaleY = v.getScaleY() * v.getHeight() / indicatorHeight;
+
+ getLocationRelativeToParentPagedView(v, mTargetViewPos);
+ float x = mTargetViewPos[0] - mIndicatorPos[0] - (1 - scaleX) * indicatorWidth / 2;
+ float y = mTargetViewPos[1] - mIndicatorPos[1] - (1 - scaleY) * indicatorHeight / 2;
+
+ if (getAlpha() > MIN_VISIBLE_ALPHA) {
+ animate()
+ .translationX(x)
+ .translationY(y)
+ .scaleX(scaleX)
+ .scaleY(scaleY)
+ .alpha(1);
+ } else {
+ setTranslationX(x);
+ setTranslationY(y);
+ setScaleX(scaleX);
+ setScaleY(scaleY);
+ animate().alpha(1);
+ }
+ mLastFocusedView = v;
+ } else {
+ if (mLastFocusedView == v) {
+ mLastFocusedView = null;
+ animate().alpha(0);
+ }
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mPendingCall != null) {
+ onFocusChange(mPendingCall.first, mPendingCall.second);
+ }
+ }
+
+ /**
+ * Gets the location of a view relative in the window, off-setting any shift due to
+ * page view scroll
+ */
+ private static void getLocationRelativeToParentPagedView(View v, int[] pos) {
+ getPagedViewScrollShift(v, sTempShift);
+ v.getLocationInWindow(sTempPos);
+ pos[0] = sTempPos[0] + sTempShift[0];
+ pos[1] = sTempPos[1] + sTempShift[1];
+ }
+
+ private static void getPagedViewScrollShift(View child, int[] shift) {
+ ViewParent parent = child.getParent();
+ if (parent instanceof PagedView) {
+ View parentView = (View) parent;
+ child.getLocationInWindow(sTempPos);
+ shift[0] = parentView.getPaddingLeft() - sTempPos[0];
+ shift[1] = -(int) child.getTranslationY();
+ } else if (parent instanceof View) {
+ getPagedViewScrollShift((View) parent, shift);
+ } else {
+ shift[0] = shift[1] = 0;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index fcedaea..f26f87c 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -18,6 +18,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
@@ -40,6 +41,7 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateInterpolator;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
@@ -72,6 +74,8 @@
private static final int CLOSE_FOLDER_DELAY_MS = 150;
private int mExpandDuration;
+ private int mMaterialExpandDuration;
+ private int mMaterialExpandStagger;
protected CellLayout mContent;
private ScrollView mScrollView;
private final LayoutInflater mInflater;
@@ -112,9 +116,7 @@
private static String sDefaultFolderName;
private static String sHintText;
- private int DRAG_MODE_NONE = 0;
- private int DRAG_MODE_REORDER = 1;
- private int mDragMode = DRAG_MODE_NONE;
+ private FocusIndicatorView mFocusIndicatorHandler;
// We avoid measuring the scroll view with a 0 width or height, as this
// results in CellLayout being measured as UNSPECIFIED, which it does
@@ -157,7 +159,9 @@
mInputMethodManager = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- mExpandDuration = res.getInteger(R.integer.config_folderAnimDuration);
+ mExpandDuration = res.getInteger(R.integer.config_folderExpandDuration);
+ mMaterialExpandDuration = res.getInteger(R.integer.config_materialFolderExpandDuration);
+ mMaterialExpandStagger = res.getInteger(R.integer.config_materialFolderExpandStagger);
if (sDefaultFolderName == null) {
sDefaultFolderName = res.getString(R.string.folder_name);
@@ -178,6 +182,11 @@
mScrollView = (ScrollView) findViewById(R.id.scroll_view);
mContent = (CellLayout) findViewById(R.id.folder_content);
+ mFocusIndicatorHandler = new FocusIndicatorView(getContext());
+ mContent.addView(mFocusIndicatorHandler, 0);
+ mFocusIndicatorHandler.getLayoutParams().height = FocusIndicatorView.DEFAULT_LAYOUT_SIZE;
+ mFocusIndicatorHandler.getLayoutParams().width = FocusIndicatorView.DEFAULT_LAYOUT_SIZE;
+
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
@@ -241,7 +250,6 @@
mLauncher.getLauncherClings().dismissFolderCling(null);
- mLauncher.getWorkspace().onDragStartedWithItem(v);
mLauncher.getWorkspace().beginDragShared(v, this);
mCurrentDragInfo = item;
@@ -443,18 +451,93 @@
mState = STATE_SMALL;
}
+ private void prepareReveal() {
+ setScaleX(1f);
+ setScaleY(1f);
+ setAlpha(1f);
+ mState = STATE_SMALL;
+ }
+
public void animateOpen() {
- positionAndSizeAsIcon();
-
if (!(getParent() instanceof DragLayer)) return;
- centerAboutIcon();
- PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1);
- PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
- PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
- final ObjectAnimator oa =
- LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
- oa.addListener(new AnimatorListenerAdapter() {
+ Animator openFolderAnim = null;
+ final Runnable onCompleteRunnable;
+ if (!Utilities.isLmp()) {
+ positionAndSizeAsIcon();
+ centerAboutIcon();
+
+ PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1);
+ PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f);
+ PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f);
+ final ObjectAnimator oa =
+ LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY);
+ oa.setDuration(mExpandDuration);
+ openFolderAnim = oa;
+
+ setLayerType(LAYER_TYPE_HARDWARE, null);
+ onCompleteRunnable = new Runnable() {
+ @Override
+ public void run() {
+ setLayerType(LAYER_TYPE_NONE, null);
+ }
+ };
+ } else {
+ prepareReveal();
+ centerAboutIcon();
+
+ int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
+ int height = getFolderHeight();
+
+ float transX = - 0.075f * (width / 2 - getPivotX());
+ float transY = - 0.075f * (height / 2 - getPivotY());
+ setTranslationX(transX);
+ setTranslationY(transY);
+ PropertyValuesHolder tx = PropertyValuesHolder.ofFloat("translationX", transX, 0);
+ PropertyValuesHolder ty = PropertyValuesHolder.ofFloat("translationY", transY, 0);
+
+ int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
+ int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
+ float radius = (float) Math.sqrt(rx * rx + ry * ry);
+ AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+ Animator reveal = LauncherAnimUtils.createCircularReveal(this, (int) getPivotX(),
+ (int) getPivotY(), 0, radius);
+ reveal.setDuration(mMaterialExpandDuration);
+ reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+ mContent.setAlpha(0f);
+ Animator iconsAlpha = LauncherAnimUtils.ofFloat(mContent, "alpha", 0f, 1f);
+ iconsAlpha.setDuration(mMaterialExpandDuration);
+ iconsAlpha.setStartDelay(mMaterialExpandStagger);
+ iconsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
+
+ mFolderName.setAlpha(0f);
+ Animator textAlpha = LauncherAnimUtils.ofFloat(mFolderName, "alpha", 0f, 1f);
+ textAlpha.setDuration(mMaterialExpandDuration);
+ textAlpha.setStartDelay(mMaterialExpandStagger);
+ textAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
+
+ Animator drift = LauncherAnimUtils.ofPropertyValuesHolder(this, tx, ty);
+ drift.setDuration(mMaterialExpandDuration);
+ drift.setStartDelay(mMaterialExpandStagger);
+ drift.setInterpolator(new LogDecelerateInterpolator(60, 0));
+
+ anim.play(drift);
+ anim.play(iconsAlpha);
+ anim.play(textAlpha);
+ anim.play(reveal);
+
+ openFolderAnim = anim;
+
+ mContent.setLayerType(LAYER_TYPE_HARDWARE, null);
+ onCompleteRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mContent.setLayerType(LAYER_TYPE_NONE, null);
+ }
+ };
+ }
+ openFolderAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
@@ -465,7 +548,10 @@
@Override
public void onAnimationEnd(Animator animation) {
mState = STATE_OPEN;
- setLayerType(LAYER_TYPE_NONE, null);
+
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
// Only show cling if we are not in the middle of a drag - this would be quite jarring.
if (!mDragController.isDragging()) {
@@ -479,9 +565,7 @@
setFocusOnFirstChild();
}
});
- oa.setDuration(mExpandDuration);
- setLayerType(LAYER_TYPE_HARDWARE, null);
- oa.start();
+ openFolderAnim.start();
// Make sure the folder picks up the last drag move even if the finger doesn't move.
if (mDragController.isDragging()) {
@@ -572,6 +656,7 @@
textView.setOnClickListener(this);
textView.setOnLongClickListener(this);
+ textView.setOnFocusChangeListener(mFocusIndicatorHandler);
// We need to check here to verify that the given item's location isn't already occupied
// by another item.
@@ -693,9 +778,6 @@
mReorderAlarm.setAlarm(REORDER_DELAY);
mPreviousTargetCell[0] = mTargetCell[0];
mPreviousTargetCell[1] = mTargetCell[1];
- mDragMode = DRAG_MODE_REORDER;
- } else {
- mDragMode = DRAG_MODE_NONE;
}
}
}
@@ -751,7 +833,6 @@
mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
}
mReorderAlarm.cancelAlarm();
- mDragMode = DRAG_MODE_NONE;
}
public void onDropCompleted(final View target, final DragObject d,
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index c0b9da7..a359f11 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -178,6 +178,7 @@
icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon);
folderInfo.addListener(icon);
+ icon.setOnFocusChangeListener(launcher.mFocusHandler);
return icon;
}
@@ -582,9 +583,10 @@
d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
if (d instanceof FastBitmapDrawable) {
FastBitmapDrawable fd = (FastBitmapDrawable) d;
- fd.addBrightness(params.overlayAlpha);
+ int oldBrightness = fd.getBrightness();
+ fd.setBrightness(params.overlayAlpha);
d.draw(canvas);
- fd.addBrightness(-params.overlayAlpha);
+ fd.setBrightness(oldBrightness);
} else {
d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255),
PorterDuff.Mode.SRC_ATOP);
diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java
index d7b960a..b1e0e68 100644
--- a/src/com/android/launcher3/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/HolographicOutlineHelper.java
@@ -20,48 +20,49 @@
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
public class HolographicOutlineHelper {
- private final Paint mHolographicPaint = new Paint();
+
+ private static final Rect sTempRect = new Rect();
+
+ private final Canvas mCanvas = new Canvas();
+ private final Paint mDrawPaint = new Paint();
private final Paint mBlurPaint = new Paint();
private final Paint mErasePaint = new Paint();
- public int mMaxOuterBlurRadius;
- public int mMinOuterBlurRadius;
+ private final BlurMaskFilter mMediumOuterBlurMaskFilter;
+ private final BlurMaskFilter mThinOuterBlurMaskFilter;
+ private final BlurMaskFilter mMediumInnerBlurMaskFilter;
- private BlurMaskFilter mExtraThickOuterBlurMaskFilter;
- private BlurMaskFilter mThickOuterBlurMaskFilter;
- private BlurMaskFilter mMediumOuterBlurMaskFilter;
- private BlurMaskFilter mThinOuterBlurMaskFilter;
- private BlurMaskFilter mThickInnerBlurMaskFilter;
- private BlurMaskFilter mExtraThickInnerBlurMaskFilter;
- private BlurMaskFilter mMediumInnerBlurMaskFilter;
+ private final BlurMaskFilter mShaowBlurMaskFilter;
+ private final int mShadowOffset;
- private static final int THICK = 0;
- private static final int MEDIUM = 1;
- private static final int EXTRA_THICK = 2;
+ /**
+ * Padding used when creating shadow bitmap;
+ */
+ final int shadowBitmapPadding;
static HolographicOutlineHelper INSTANCE;
private HolographicOutlineHelper(Context context) {
final float scale = LauncherAppState.getInstance().getScreenDensity();
- mMinOuterBlurRadius = (int) (scale * 1.0f);
- mMaxOuterBlurRadius = (int) (scale * 12.0f);
-
- mExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER);
- mThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER);
mMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
mThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
- mExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL);
- mThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
mMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
- mHolographicPaint.setFilterBitmap(true);
- mHolographicPaint.setAntiAlias(true);
+ mShaowBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
+ mShadowOffset = (int) (scale * 2.0f);
+ shadowBitmapPadding = (int) (scale * 4.0f);
+
+ mDrawPaint.setFilterBitmap(true);
+ mDrawPaint.setAntiAlias(true);
mBlurPaint.setFilterBitmap(true);
mBlurPaint.setAntiAlias(true);
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
@@ -77,37 +78,15 @@
}
/**
- * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
- * pages.
- */
- public static float highlightAlphaInterpolator(float r) {
- float maxAlpha = 0.6f;
- return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
- }
-
- /**
- * Returns the interpolated view alpha for the effect we want when scrolling pages.
- */
- public static float viewAlphaInterpolator(float r) {
- final float pivot = 0.95f;
- if (r < pivot) {
- return (float) Math.pow(r / pivot, 1.5f);
- } else {
- return 1.0f;
- }
- }
-
- /**
* Applies a more expensive and accurate outline to whatever is currently drawn in a specified
* bitmap.
*/
void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor, int thickness) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true,
- thickness);
+ int outlineColor) {
+ applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true);
}
void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor, boolean clipAlpha, int thickness) {
+ int outlineColor, boolean clipAlpha) {
// We start by removing most of the alpha channel so as to ignore shadows, and
// other types of partial transparency when defining the shape of the object
@@ -127,50 +106,18 @@
Bitmap glowShape = srcDst.extractAlpha();
// calculate the outer blur first
- BlurMaskFilter outerBlurMaskFilter;
- switch (thickness) {
- case EXTRA_THICK:
- outerBlurMaskFilter = mExtraThickOuterBlurMaskFilter;
- break;
- case THICK:
- outerBlurMaskFilter = mThickOuterBlurMaskFilter;
- break;
- case MEDIUM:
- outerBlurMaskFilter = mMediumOuterBlurMaskFilter;
- break;
- default:
- throw new RuntimeException("Invalid blur thickness");
- }
- mBlurPaint.setMaskFilter(outerBlurMaskFilter);
+ mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter);
int[] outerBlurOffset = new int[2];
Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset);
- if (thickness == EXTRA_THICK) {
- mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter);
- } else {
- mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter);
- }
+ mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter);
int[] brightOutlineOffset = new int[2];
Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset);
// calculate the inner blur
srcDstCanvas.setBitmap(glowShape);
srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
- BlurMaskFilter innerBlurMaskFilter;
- switch (thickness) {
- case EXTRA_THICK:
- innerBlurMaskFilter = mExtraThickInnerBlurMaskFilter;
- break;
- case THICK:
- innerBlurMaskFilter = mThickInnerBlurMaskFilter;
- break;
- case MEDIUM:
- innerBlurMaskFilter = mMediumInnerBlurMaskFilter;
- break;
- default:
- throw new RuntimeException("Invalid blur thickness");
- }
- mBlurPaint.setMaskFilter(innerBlurMaskFilter);
+ mBlurPaint.setMaskFilter(mMediumInnerBlurMaskFilter);
int[] thickInnerBlurOffset = new int[2];
Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset);
@@ -186,16 +133,16 @@
// draw the inner and outer blur
srcDstCanvas.setBitmap(srcDst);
srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
- mHolographicPaint.setColor(color);
+ mDrawPaint.setColor(color);
srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
- mHolographicPaint);
+ mDrawPaint);
srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
- mHolographicPaint);
+ mDrawPaint);
// draw the bright outline
- mHolographicPaint.setColor(outlineColor);
+ mDrawPaint.setColor(outlineColor);
srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1],
- mHolographicPaint);
+ mDrawPaint);
// cleanup
srcDstCanvas.setBitmap(null);
@@ -205,25 +152,52 @@
glowShape.recycle();
}
- void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK);
- }
+ Bitmap createMediumDropShadow(BubbleTextView view) {
+ final Bitmap result = Bitmap.createBitmap(
+ view.getWidth() + shadowBitmapPadding + shadowBitmapPadding,
+ view.getHeight() + shadowBitmapPadding + shadowBitmapPadding + mShadowOffset,
+ Bitmap.Config.ARGB_8888);
- void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK);
- }
+ mCanvas.setBitmap(result);
- void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor, boolean clipAlpha) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha,
- MEDIUM);
- }
+ final Rect clipRect = sTempRect;
+ view.getDrawingRect(sTempRect);
+ // adjust the clip rect so that we don't include the text label
+ clipRect.bottom = view.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V
+ + view.getLayout().getLineTop(0);
- void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
- int outlineColor) {
- applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM);
- }
+ // Draw the View into the bitmap.
+ // The translate of scrollX and scrollY is necessary when drawing TextViews, because
+ // they set scrollX and scrollY to large values to achieve centered text
+ mCanvas.save();
+ mCanvas.scale(view.getScaleX(), view.getScaleY(),
+ view.getWidth() / 2 + shadowBitmapPadding,
+ view.getHeight() / 2 + shadowBitmapPadding);
+ mCanvas.translate(-view.getScrollX() + shadowBitmapPadding,
+ -view.getScrollY() + shadowBitmapPadding);
+ mCanvas.clipRect(clipRect, Op.REPLACE);
+ view.draw(mCanvas);
+ mCanvas.restore();
+ int[] blurOffst = new int[2];
+ mBlurPaint.setMaskFilter(mShaowBlurMaskFilter);
+ Bitmap blurBitmap = result.extractAlpha(mBlurPaint, blurOffst);
+
+ mCanvas.save();
+ mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
+ mCanvas.translate(blurOffst[0], blurOffst[1]);
+
+ mDrawPaint.setColor(Color.BLACK);
+ mDrawPaint.setAlpha(30);
+ mCanvas.drawBitmap(blurBitmap, 0, 0, mDrawPaint);
+
+ mDrawPaint.setAlpha(60);
+ mCanvas.drawBitmap(blurBitmap, 0, mShadowOffset, mDrawPaint);
+ mCanvas.restore();
+
+ mCanvas.setBitmap(null);
+ blurBitmap.recycle();
+
+ return result;
+ }
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 79cac8f..3d6befa 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -159,6 +159,7 @@
allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
mLauncher.setAllAppsButton(allAppsButton);
allAppsButton.setOnClickListener(mLauncher);
+ allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
}
// Note: We do this to ensure that the hotseat is always laid out in the orientation of
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 06b7775..76a85ca 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -146,6 +146,10 @@
return getFullResDefaultActivityIcon();
}
+ public int getFullResIconDpi() {
+ return mIconDpi;
+ }
+
public Drawable getFullResIcon(ResolveInfo info) {
return getFullResIcon(info.activityInfo);
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8995856..5d9ff1d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -82,7 +82,6 @@
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.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -100,6 +99,7 @@
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.PagedView.PageSwitchListener;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
@@ -258,7 +258,7 @@
private View mWeightWatcher;
private LauncherClings mLauncherClings;
- private AppWidgetManager mAppWidgetManager;
+ private AppWidgetManagerCompat mAppWidgetManager;
private LauncherAppWidgetHost mAppWidgetHost;
private ItemInfo mPendingAddInfo = new ItemInfo();
@@ -381,6 +381,8 @@
private Stats mStats;
+ FocusIndicatorView mFocusHandler;
+
static boolean isPropertyEnabled(String propertyName) {
return Log.isLoggable(propertyName, Log.VERBOSE);
}
@@ -437,7 +439,7 @@
mStats = new Stats(this);
- mAppWidgetManager = AppWidgetManager.getInstance(this);
+ mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
mAppWidgetHost.startListening();
@@ -1024,10 +1026,6 @@
// Resets the previous workspace icon press state
mWaitingForResume.setStayPressed(false);
}
- if (mAppsCustomizeContent != null) {
- // Resets the previous all apps icon press state
- mAppsCustomizeContent.resetDrawableState();
- }
// It is possible that widgets can receive updates while launcher is not in the foreground.
// Consequently, the widgets will be inflated in the orientation of the foreground activity
@@ -1278,6 +1276,7 @@
final DragController dragController = mDragController;
mLauncherView = findViewById(R.id.launcher);
+ mFocusHandler = (FocusIndicatorView) findViewById(R.id.focus_indicator);
mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
mWorkspace.setPageSwitchListener(this);
@@ -1417,6 +1416,7 @@
BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
favorite.applyFromShortcutInfo(info, mIconCache, true);
favorite.setOnClickListener(this);
+ favorite.setOnFocusChangeListener(mFocusHandler);
return favorite;
}
@@ -1570,6 +1570,7 @@
launcherInfo.spanY = spanXY[1];
launcherInfo.minSpanX = mPendingAddInfo.minSpanX;
launcherInfo.minSpanY = mPendingAddInfo.minSpanY;
+ launcherInfo.user = mAppWidgetManager.getUser(appWidgetInfo);
LauncherModel.addItemToDatabase(this, launcherInfo,
container, screenId, cellXY[0], cellXY[1], false);
@@ -2195,10 +2196,9 @@
mPendingAddWidgetId = appWidgetId;
// Launch over to configure widget, if needed
- Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
- intent.setComponent(appWidgetInfo.configure);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_APPWIDGET);
+ mAppWidgetManager.startConfigActivity(appWidgetInfo, appWidgetId, this,
+ mAppWidgetHost, REQUEST_CREATE_APPWIDGET);
+
} else {
// Otherwise just add it
Runnable onComplete = new Runnable() {
@@ -2282,14 +2282,8 @@
appWidgetId = getAppWidgetHost().allocateAppWidgetId();
Bundle options = info.bindOptions;
- boolean success = false;
- if (options != null) {
- success = mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
- info.componentName, options);
- } else {
- success = mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
- info.componentName);
- }
+ boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
+ appWidgetId, info.info, options);
if (success) {
addAppWidgetImpl(appWidgetId, info, null, info.info);
} else {
@@ -2297,6 +2291,8 @@
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);
+ mAppWidgetManager.getUser(mPendingAddWidgetInfo)
+ .addToIntent(intent, AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE);
// TODO: we need to make sure that this accounts for the options bundle.
// intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
startActivityForResult(intent, REQUEST_BIND_APPWIDGET);
@@ -2447,6 +2443,8 @@
}
} else if (v == mAllAppsButton) {
onClickAllAppsButton(v);
+ } else if (tag instanceof AppInfo) {
+ startAppShortcutOrInfoActivity(v);
} else if (tag instanceof LauncherAppWidgetInfo) {
if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v);
@@ -2454,6 +2452,10 @@
}
}
+ public void onClickPagedViewIcon(View v) {
+ startAppShortcutOrInfoActivity(v);
+ }
+
public boolean onTouch(View v, MotionEvent event) {
return false;
}
@@ -2471,10 +2473,8 @@
mPendingAddInfo.copyFrom(info);
mPendingAddWidgetId = widgetId;
- Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
- intent.setComponent(appWidgetInfo.configure);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, info.appWidgetId);
- Utilities.startActivityForResultSafely(this, intent, REQUEST_RECONFIGURE_APPWIDGET);
+ AppWidgetManagerCompat.getInstance(this).startConfigActivity(appWidgetInfo,
+ info.appWidgetId, this, mAppWidgetHost, REQUEST_RECONFIGURE_APPWIDGET);
}
}
}
@@ -2535,17 +2535,6 @@
}
/**
- * Event handler for a paged view icon click.
- * @param v The view that was clicked.
- * @param appInfo The {link AppInfo} of the view.
- */
- public void onClickPagedViewIcon(View v, AppInfo appInfo) {
- if (LOGD) Log.d(TAG, "onClickPagedViewIcon");
- startActivitySafely(v, appInfo.intent, appInfo);
- getStats().recordLaunch(appInfo.intent);
- }
-
- /**
* Event handler for an app shortcut click.
*
* @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
@@ -2582,7 +2571,7 @@
builder.setPositiveButton(R.string.abandoned_search,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- startAppShortcutActivity(v);
+ startAppShortcutOrInfoActivity(v);
}
}
);
@@ -2599,24 +2588,29 @@
}
// Start activities
- startAppShortcutActivity(v);
+ startAppShortcutOrInfoActivity(v);
}
- private void startAppShortcutActivity(View v) {
+ private void startAppShortcutOrInfoActivity(View v) {
Object tag = v.getTag();
- if (!(tag instanceof ShortcutInfo)) {
- throw new IllegalArgumentException("Input must be a Shortcut");
- }
- final ShortcutInfo shortcut = (ShortcutInfo) tag;
- final Intent intent = shortcut.intent;
+ final ShortcutInfo shortcut;
+ final Intent intent;
+ if (tag instanceof ShortcutInfo) {
+ shortcut = (ShortcutInfo) tag;
+ intent = shortcut.intent;
+ int[] pos = new int[2];
+ v.getLocationOnScreen(pos);
+ intent.setSourceBounds(new Rect(pos[0], pos[1],
+ pos[0] + v.getWidth(), pos[1] + v.getHeight()));
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- intent.setSourceBounds(new Rect(pos[0], pos[1],
- pos[0] + v.getWidth(), pos[1] + v.getHeight()));
+ } else if (tag instanceof AppInfo) {
+ shortcut = null;
+ intent = ((AppInfo) tag).intent;
+ } else {
+ throw new IllegalArgumentException("Input must be a Shortcut or AppInfo");
+ }
boolean success = startActivitySafely(v, intent, tag);
-
mStats.recordLaunch(intent, shortcut);
if (success && v instanceof BubbleTextView) {
@@ -2910,7 +2904,10 @@
ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha,
scaleX, scaleY);
- oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration));
+ if (Utilities.isLmp()) {
+ oa.setInterpolator(new LogDecelerateInterpolator(100, 0));
+ }
+ oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration));
oa.start();
}
@@ -2927,7 +2924,7 @@
copyFolderIconToImage(fi);
ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha,
scaleX, scaleY);
- oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration));
+ oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration));
oa.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -3284,8 +3281,7 @@
int allAppsButtonSize = LauncherAppState.getInstance().
getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
float startRadius = isWidgetTray ? 0 : allAppsButtonSize / 2;
- ValueAnimator reveal = (ValueAnimator)
- LauncherAnimUtils.createCircularReveal(revealView, width / 2,
+ Animator reveal = LauncherAnimUtils.createCircularReveal(revealView, width / 2,
height / 2, startRadius, revealRadius);
reveal.setDuration(revealDuration);
reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
@@ -4377,15 +4373,9 @@
Bundle options =
AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
- boolean success = false;
int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
- if (options != null) {
- success = mAppWidgetManager.bindAppWidgetIdIfAllowed(newWidgetId,
- appWidgetInfo.provider, options);
- } else {
- success = mAppWidgetManager.bindAppWidgetIdIfAllowed(newWidgetId,
- appWidgetInfo.provider);
- }
+ boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
+ newWidgetId, appWidgetInfo, options);
// TODO consider showing a permission dialog when the widget is clicked.
if (!success) {
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 64e82c7..1ea562b 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -299,36 +299,26 @@
Set<String> savedIds = getSavedIdsByType(Key.FAVORITE, in);
if (DEBUG) Log.d(TAG, "favorite savedIds.size()=" + savedIds.size());
- // Don't backup apps in other profiles for now.
- UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
- long userSerialNumber =
- UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle);
-
// persist things that have changed since the last backup
ContentResolver cr = mContext.getContentResolver();
+ // Don't backup apps in other profiles for now.
Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
- null, null, null);
+ getUserSelectionArg(), null, null);
Set<String> currentIds = new HashSet<String>(cursor.getCount());
try {
cursor.moveToPosition(-1);
while(cursor.moveToNext()) {
final long id = cursor.getLong(ID_INDEX);
- final long profileId = cursor.getLong(PROFILE_ID_INDEX);
- if (userSerialNumber == profileId) {
- final long updateTime = cursor.getLong(ID_MODIFIED);
- Key key = getKey(Key.FAVORITE, id);
- keys.add(key);
- final String backupKey = keyToBackupKey(key);
- currentIds.add(backupKey);
- if (!savedIds.contains(backupKey) || updateTime >= in.t) {
- byte[] blob = packFavorite(cursor);
- writeRowToBackup(key, blob, out, data);
- } else {
- if (VERBOSE) Log.v(TAG, "favorite " + id + " was too old: " + updateTime);
- }
+ final long updateTime = cursor.getLong(ID_MODIFIED);
+ Key key = getKey(Key.FAVORITE, id);
+ keys.add(key);
+ final String backupKey = keyToBackupKey(key);
+ currentIds.add(backupKey);
+ if (!savedIds.contains(backupKey) || updateTime >= in.t) {
+ byte[] blob = packFavorite(cursor);
+ writeRowToBackup(key, blob, out, data);
} else {
- if (VERBOSE) Log.v(TAG, "favorite " + id + " is for other profile: "
- + profileId);
+ if (VERBOSE) Log.v(TAG, "favorite " + id + " was too old: " + updateTime);
}
}
} finally {
@@ -469,20 +459,19 @@
}
final ContentResolver cr = mContext.getContentResolver();
final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
+ final UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
// read the old ID set
Set<String> savedIds = getSavedIdsByType(Key.ICON, in);
if (DEBUG) Log.d(TAG, "icon savedIds.size()=" + savedIds.size());
// Don't backup apps in other profiles for now.
- UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
- long userSerialNumber =
- UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle);
int startRows = out.rows;
if (DEBUG) Log.d(TAG, "starting here: " + startRows);
+
String where = "(" + Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPLICATION + " OR " +
Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_SHORTCUT + ") AND " +
- Favorites.PROFILE_ID + "=" + userSerialNumber;
+ getUserSelectionArg();
Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
where, null, null);
Set<String> currentIds = new HashSet<String>(cursor.getCount());
@@ -617,7 +606,8 @@
int startRows = out.rows;
if (DEBUG) Log.d(TAG, "starting here: " + startRows);
- String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET;
+ String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET + " AND "
+ + getUserSelectionArg();
Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
where, null, null);
Set<String> currentIds = new HashSet<String>(cursor.getCount());
@@ -1192,6 +1182,11 @@
return true;
}
+ private String getUserSelectionArg() {
+ return Favorites.PROFILE_ID + '=' + UserManagerCompat.getInstance(mContext)
+ .getSerialNumberForUser(UserHandleCompat.myUserHandle());
+ }
+
private class KeyParsingException extends Throwable {
private KeyParsingException(Throwable cause) {
super(cause);
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 4c9d1a7..bcb4501 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -30,7 +30,6 @@
import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
@@ -52,7 +51,7 @@
import android.util.Log;
import android.util.Pair;
-import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
@@ -3040,11 +3039,11 @@
public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {
PackageManager packageManager = context.getPackageManager();
final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
- widgetsAndShortcuts.addAll(AppWidgetManager.getInstance(context).getInstalledProviders());
+ widgetsAndShortcuts.addAll(AppWidgetManagerCompat.getInstance(context).getAllProviders());
+
Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));
- Collections.sort(widgetsAndShortcuts,
- new LauncherModel.WidgetAndShortcutNameComparator(packageManager));
+ Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));
return widgetsAndShortcuts;
}
@@ -3390,44 +3389,6 @@
return null;
}
- /**
- * Returns a list of all the widgets that can handle configuration with a particular mimeType.
- */
- List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {
- final PackageManager packageManager = context.getPackageManager();
- final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =
- new ArrayList<WidgetMimeTypeHandlerData>();
-
- final Intent supportsIntent =
- new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);
- supportsIntent.setType(mimeType);
-
- // Create a set of widget configuration components that we can test against
- final List<AppWidgetProviderInfo> widgets =
- AppWidgetManager.getInstance(context).getInstalledProviders();
- final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =
- new HashMap<ComponentName, AppWidgetProviderInfo>();
- for (AppWidgetProviderInfo info : widgets) {
- configurationComponentToWidget.put(info.configure, info);
- }
-
- // Run through each of the intents that can handle this type of clip data, and cross
- // reference them with the components that are actual configuration components
- final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo info : activities) {
- final ActivityInfo activityInfo = info.activityInfo;
- final ComponentName infoComponent = new ComponentName(activityInfo.packageName,
- activityInfo.name);
- if (configurationComponentToWidget.containsKey(infoComponent)) {
- supportedConfigurationActivities.add(
- new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,
- configurationComponentToWidget.get(infoComponent)));
- }
- }
- return supportedConfigurationActivities;
- }
-
ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
@@ -3570,14 +3531,6 @@
return 0;
}
};
- public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() {
- final Collator collator = Collator.getInstance();
- return new Comparator<AppWidgetProviderInfo>() {
- public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {
- return collator.compare(a.label.toString().trim(), b.label.toString().trim());
- }
- };
- }
static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {
if (info.activityInfo != null) {
return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
@@ -3618,11 +3571,14 @@
}
};
public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
- private Collator mCollator;
- private PackageManager mPackageManager;
- private HashMap<Object, String> mLabelCache;
- WidgetAndShortcutNameComparator(PackageManager pm) {
- mPackageManager = pm;
+ private final AppWidgetManagerCompat mManager;
+ private final PackageManager mPackageManager;
+ private final HashMap<Object, String> mLabelCache;
+ private final Collator mCollator;
+
+ WidgetAndShortcutNameComparator(Context context) {
+ mManager = AppWidgetManagerCompat.getInstance(context);
+ mPackageManager = context.getPackageManager();
mLabelCache = new HashMap<Object, String>();
mCollator = Collator.getInstance();
}
@@ -3631,17 +3587,17 @@
if (mLabelCache.containsKey(a)) {
labelA = mLabelCache.get(a);
} else {
- labelA = (a instanceof AppWidgetProviderInfo) ?
- ((AppWidgetProviderInfo) a).label :
- ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();
+ labelA = (a instanceof AppWidgetProviderInfo)
+ ? mManager.loadLabel((AppWidgetProviderInfo) a)
+ : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();
mLabelCache.put(a, labelA);
}
if (mLabelCache.containsKey(b)) {
labelB = mLabelCache.get(b);
} else {
- labelB = (b instanceof AppWidgetProviderInfo) ?
- ((AppWidgetProviderInfo) b).label :
- ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();
+ labelB = (b instanceof AppWidgetProviderInfo)
+ ? mManager.loadLabel((AppWidgetProviderInfo) b)
+ : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();
mLabelCache.put(b, labelB);
}
return mCollator.compare(labelA, labelB);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index af65536..842e0b0 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -1650,8 +1650,10 @@
resolved = systemApp;
}
final ActivityInfo info = resolved.activityInfo;
- final Intent intent = buildMainIntent();
- intent.setComponent(new ComponentName(info.packageName, info.name));
+ final Intent intent = mPackageManager.getLaunchIntentForPackage(info.packageName);
+ if (intent == null) {
+ return -1;
+ }
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 0dbcd97..54aa24e 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -74,11 +74,12 @@
private static final int MIN_LENGTH_FOR_FLING = 25;
protected static final int PAGE_SNAP_ANIMATION_DURATION = 750;
+ protected static final int OVER_SCROLL_PAGE_SNAP_ANIMATION_DURATION = 350;
protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
protected static final float NANOTIME_DIV = 1000000000.0f;
private static final float OVERSCROLL_ACCELERATE_FACTOR = 2;
- private static final float OVERSCROLL_DAMP_FACTOR = 0.14f;
+ private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
// The page is moved more than halfway, automatically move to the next page on touch up.
@@ -1601,29 +1602,20 @@
return f * f * f + 1.0f;
}
- protected void acceleratedOverScroll(float amount) {
+ protected float acceleratedOverFactor(float amount) {
int screenSize = getViewportWidth();
// We want to reach the max over scroll effect when the user has
// over scrolled half the size of the screen
float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize);
- if (f == 0) return;
+ if (f == 0) return 0;
// Clamp this factor, f, to -1 < f < 1
if (Math.abs(f) >= 1) {
f /= Math.abs(f);
}
-
- int overScrollAmount = (int) Math.round(f * screenSize);
- if (amount < 0) {
- mOverScrollX = overScrollAmount;
- super.scrollTo(0, getScrollY());
- } else {
- mOverScrollX = mMaxScrollX + overScrollAmount;
- super.scrollTo(mMaxScrollX, getScrollY());
- }
- invalidate();
+ return f;
}
protected void dampedOverScroll(float amount) {
@@ -1642,10 +1634,10 @@
int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
if (amount < 0) {
mOverScrollX = overScrollAmount;
- super.scrollTo(0, getScrollY());
+ super.scrollTo(mOverScrollX, getScrollY());
} else {
mOverScrollX = mMaxScrollX + overScrollAmount;
- super.scrollTo(mMaxScrollX, getScrollY());
+ super.scrollTo(mOverScrollX, getScrollY());
}
invalidate();
}
@@ -2145,8 +2137,20 @@
return minDistanceFromScreenCenterIndex;
}
+ protected boolean isInOverScroll() {
+ return (mOverScrollX > mMaxScrollX || mOverScrollX < 0);
+ }
+
+ protected int getPageSnapDuration() {
+ if (isInOverScroll()) {
+ return OVER_SCROLL_PAGE_SNAP_ANIMATION_DURATION;
+ }
+ return PAGE_SNAP_ANIMATION_DURATION;
+
+ }
+
protected void snapToDestination() {
- snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
+ snapToPage(getPageNearestToCenterOfScreen(), getPageSnapDuration());
}
private static class ScrollInterpolator implements Interpolator {
@@ -2177,10 +2181,10 @@
int delta = newX - mUnboundedScrollX;
int duration = 0;
- if (Math.abs(velocity) < mMinFlingVelocity) {
+ if (Math.abs(velocity) < mMinFlingVelocity || isInOverScroll()) {
// If the velocity is low enough, then treat this more as an automatic page advance
// as opposed to an apparent physical response to flinging
- snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
+ snapToPage(whichPage, getPageSnapDuration());
return;
}
@@ -2204,11 +2208,11 @@
}
protected void snapToPage(int whichPage) {
- snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
+ snapToPage(whichPage, getPageSnapDuration());
}
protected void snapToPageImmediately(int whichPage) {
- snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true, null);
+ snapToPage(whichPage, getPageSnapDuration(), true, null);
}
protected void snapToPage(int whichPage, int duration) {
diff --git a/src/com/android/launcher3/PagedViewIcon.java b/src/com/android/launcher3/PagedViewIcon.java
deleted file mode 100644
index e819d5e..0000000
--- a/src/com/android/launcher3/PagedViewIcon.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Region;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.widget.TextView;
-
-/**
- * An icon on a PagedView, specifically for items in the launcher's paged view (with compound
- * drawables on the top).
- */
-public class PagedViewIcon extends TextView {
- /** A simple callback interface to allow a PagedViewIcon to notify when it has been pressed */
- public static interface PressedCallback {
- void iconPressed(PagedViewIcon icon);
- }
-
- @SuppressWarnings("unused")
- private static final String TAG = "PagedViewIcon";
- private static final float PRESS_ALPHA = 0.4f;
-
- private PagedViewIcon.PressedCallback mPressedCallback;
- private boolean mLockDrawableState = false;
-
- private Bitmap mIcon;
-
- public PagedViewIcon(Context context) {
- this(context, null);
- }
-
- public PagedViewIcon(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public void onFinishInflate() {
- 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.allAppsIconTextSizePx);
- }
-
- public void applyFromApplicationInfo(AppInfo info, boolean scaleUp,
- PagedViewIcon.PressedCallback cb) {
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
- mIcon = info.iconBitmap;
- mPressedCallback = cb;
- Drawable icon = Utilities.createIconDrawable(mIcon);
- icon.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx);
- setCompoundDrawables(null, icon, null, null);
- setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
- setText(info.title);
- if (info.contentDescription != null) {
- setContentDescription(info.contentDescription);
- }
- setTag(info);
- }
-
- public void lockDrawableState() {
- mLockDrawableState = true;
- }
-
- public void resetDrawableState() {
- mLockDrawableState = false;
- post(new Runnable() {
- @Override
- public void run() {
- refreshDrawableState();
- }
- });
- }
-
- protected void drawableStateChanged() {
- super.drawableStateChanged();
-
- // We keep in the pressed state until resetDrawableState() is called to reset the press
- // feedback
- if (isPressed()) {
- setAlpha(PRESS_ALPHA);
- if (mPressedCallback != null) {
- mPressedCallback.iconPressed(this);
- }
- } else if (!mLockDrawableState) {
- setAlpha(1f);
- }
- }
-}
diff --git a/src/com/android/launcher3/PagedViewWidget.java b/src/com/android/launcher3/PagedViewWidget.java
index db4aeb9..e6e11a3 100644
--- a/src/com/android/launcher3/PagedViewWidget.java
+++ b/src/com/android/launcher3/PagedViewWidget.java
@@ -30,6 +30,8 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
/**
* The linear layout used strictly for the widget/wallpaper tab of the customization tray
*/
@@ -127,7 +129,7 @@
image.setMaxWidth(maxWidth);
}
final TextView name = (TextView) findViewById(R.id.widget_name);
- name.setText(info.label);
+ name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
final TextView dims = (TextView) findViewById(R.id.widget_dims);
if (dims != null) {
int hSpan = Math.min(cellSpan[0], (int) grid.numColumns);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index f70fc4d..f20f261 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -78,7 +78,7 @@
/**
* Returns a FastBitmapDrawable with the icon, accurately sized.
*/
- static FastBitmapDrawable createIconDrawable(Bitmap icon) {
+ public static FastBitmapDrawable createIconDrawable(Bitmap icon) {
FastBitmapDrawable d = new FastBitmapDrawable(icon);
d.setFilterBitmap(true);
resizeIconDrawable(d);
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 1b37700..5aa7190 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -5,7 +5,6 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.database.Cursor;
@@ -29,6 +28,8 @@
import android.os.AsyncTask;
import android.util.Log;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@@ -42,124 +43,123 @@
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
-abstract class SoftReferenceThreadLocal<T> {
- private ThreadLocal<SoftReference<T>> mThreadLocal;
- public SoftReferenceThreadLocal() {
- mThreadLocal = new ThreadLocal<SoftReference<T>>();
- }
+public class WidgetPreviewLoader {
- abstract T initialValue();
+ private static abstract class SoftReferenceThreadLocal<T> {
+ private ThreadLocal<SoftReference<T>> mThreadLocal;
+ public SoftReferenceThreadLocal() {
+ mThreadLocal = new ThreadLocal<SoftReference<T>>();
+ }
- public void set(T t) {
- mThreadLocal.set(new SoftReference<T>(t));
- }
+ abstract T initialValue();
- public T get() {
- SoftReference<T> reference = mThreadLocal.get();
- T obj;
- if (reference == null) {
- obj = initialValue();
- mThreadLocal.set(new SoftReference<T>(obj));
- return obj;
- } else {
- obj = reference.get();
- if (obj == null) {
+ public void set(T t) {
+ mThreadLocal.set(new SoftReference<T>(t));
+ }
+
+ public T get() {
+ SoftReference<T> reference = mThreadLocal.get();
+ T obj;
+ if (reference == null) {
obj = initialValue();
mThreadLocal.set(new SoftReference<T>(obj));
+ return obj;
+ } else {
+ obj = reference.get();
+ if (obj == null) {
+ obj = initialValue();
+ mThreadLocal.set(new SoftReference<T>(obj));
+ }
+ return obj;
}
- return obj;
}
}
-}
-class CanvasCache extends SoftReferenceThreadLocal<Canvas> {
- @Override
- protected Canvas initialValue() {
- return new Canvas();
+ private static class CanvasCache extends SoftReferenceThreadLocal<Canvas> {
+ @Override
+ protected Canvas initialValue() {
+ return new Canvas();
+ }
}
-}
-class PaintCache extends SoftReferenceThreadLocal<Paint> {
- @Override
- protected Paint initialValue() {
- return null;
+ private static class PaintCache extends SoftReferenceThreadLocal<Paint> {
+ @Override
+ protected Paint initialValue() {
+ return null;
+ }
}
-}
-class BitmapCache extends SoftReferenceThreadLocal<Bitmap> {
- @Override
- protected Bitmap initialValue() {
- return null;
+ private static class BitmapCache extends SoftReferenceThreadLocal<Bitmap> {
+ @Override
+ protected Bitmap initialValue() {
+ return null;
+ }
}
-}
-class RectCache extends SoftReferenceThreadLocal<Rect> {
- @Override
- protected Rect initialValue() {
- return new Rect();
+ private static class RectCache extends SoftReferenceThreadLocal<Rect> {
+ @Override
+ protected Rect initialValue() {
+ return new Rect();
+ }
}
-}
-class BitmapFactoryOptionsCache extends SoftReferenceThreadLocal<BitmapFactory.Options> {
- @Override
- protected BitmapFactory.Options initialValue() {
- return new BitmapFactory.Options();
+ private static class BitmapFactoryOptionsCache extends
+ SoftReferenceThreadLocal<BitmapFactory.Options> {
+ @Override
+ protected BitmapFactory.Options initialValue() {
+ return new BitmapFactory.Options();
+ }
}
-}
-public class WidgetPreviewLoader {
- static final String TAG = "WidgetPreviewLoader";
- static final String ANDROID_INCREMENTAL_VERSION_NAME_KEY = "android.incremental.version";
+ private static final String TAG = "WidgetPreviewLoader";
+ private static final String ANDROID_INCREMENTAL_VERSION_NAME_KEY = "android.incremental.version";
+
+ private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f;
+ private static final HashSet<String> sInvalidPackages = new HashSet<String>();
+
+ // Used for drawing shortcut previews
+ private final BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache();
+ private final PaintCache mCachedShortcutPreviewPaint = new PaintCache();
+ private final CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache();
+
+ // Used for drawing widget previews
+ private final CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache();
+ private final RectCache mCachedAppWidgetPreviewSrcRect = new RectCache();
+ private final RectCache mCachedAppWidgetPreviewDestRect = new RectCache();
+ private final PaintCache mCachedAppWidgetPreviewPaint = new PaintCache();
+ private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
+ private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
+
+ 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;
+ private final IconCache mIconCache;
+ private final AppWidgetManagerCompat mManager;
private int mPreviewBitmapWidth;
private int mPreviewBitmapHeight;
private String mSize;
- private Context mContext;
- private PackageManager mPackageManager;
private PagedViewCellLayout mWidgetSpacingLayout;
- // Used for drawing shortcut previews
- private BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache();
- private PaintCache mCachedShortcutPreviewPaint = new PaintCache();
- private CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache();
-
- // Used for drawing widget previews
- private CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache();
- private RectCache mCachedAppWidgetPreviewSrcRect = new RectCache();
- private RectCache mCachedAppWidgetPreviewDestRect = new RectCache();
- private PaintCache mCachedAppWidgetPreviewPaint = new PaintCache();
- private PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
private String mCachedSelectQuery;
- private BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
- private int mAppIconSize;
- private IconCache mIconCache;
-
- private static final float sWidgetPreviewIconPaddingPercentage = 0.25f;
private CacheDb mDb;
- private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews;
- private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps;
- private final static HashSet<String> sInvalidPackages;
-
private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
- static {
- sInvalidPackages = new HashSet<String>();
- }
-
public WidgetPreviewLoader(Context context) {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
mContext = context;
- mPackageManager = mContext.getPackageManager();
mAppIconSize = grid.iconSizePx;
mIconCache = app.getIconCache();
+ mManager = AppWidgetManagerCompat.getInstance(context);
+
mDb = app.getWidgetPreviewCacheDb();
- mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>();
- mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>();
SharedPreferences sp = context.getSharedPreferences(
LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
@@ -175,7 +175,7 @@
editor.commit();
}
}
-
+
public void recreateDb() {
LauncherAppState app = LauncherAppState.getInstance();
app.recreateWidgetPreviewDb();
@@ -328,7 +328,7 @@
String output;
if (o instanceof AppWidgetProviderInfo) {
sb.append(WIDGET_PREFIX);
- sb.append(((AppWidgetProviderInfo) o).provider.flattenToString());
+ sb.append(((AppWidgetProviderInfo) o).toString());
output = sb.toString();
sb.setLength(0);
} else {
@@ -413,7 +413,7 @@
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
}
- public static void removeItemFromDb(final CacheDb cacheDb, final String objectName) {
+ private static void removeItemFromDb(final CacheDb cacheDb, final String objectName) {
new AsyncTask<Void, Void, Void>() {
public Void doInBackground(Void ... args) {
SQLiteDatabase db = cacheDb.getWritableDatabase();
@@ -473,7 +473,7 @@
}
}
- public Bitmap generatePreview(Object info, Bitmap preview) {
+ private Bitmap generatePreview(Object info, Bitmap preview) {
if (preview != null &&
(preview.getWidth() != mPreviewBitmapWidth ||
preview.getHeight() != mPreviewBitmapHeight)) {
@@ -491,8 +491,8 @@
int[] cellSpans = Launcher.getSpanForWidget(mContext, info);
int maxWidth = maxWidthForWidgetPreview(cellSpans[0]);
int maxHeight = maxHeightForWidgetPreview(cellSpans[1]);
- return generateWidgetPreview(info.provider, info.previewImage, info.icon,
- cellSpans[0], cellSpans[1], maxWidth, maxHeight, preview, null);
+ return generateWidgetPreview(info, cellSpans[0], cellSpans[1],
+ maxWidth, maxHeight, preview, null);
}
public int maxWidthForWidgetPreview(int spanX) {
@@ -505,22 +505,20 @@
mWidgetSpacingLayout.estimateCellHeight(spanY));
}
- public Bitmap generateWidgetPreview(ComponentName provider, int previewImage,
- int iconId, int cellHSpan, int cellVSpan, int maxPreviewWidth, int maxPreviewHeight,
- Bitmap preview, int[] preScaledWidthOut) {
+ public Bitmap generateWidgetPreview(AppWidgetProviderInfo info, int cellHSpan, int cellVSpan,
+ int maxPreviewWidth, int maxPreviewHeight, Bitmap preview, int[] preScaledWidthOut) {
// Load the preview image if possible
- String packageName = provider.getPackageName();
if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE;
if (maxPreviewHeight < 0) maxPreviewHeight = Integer.MAX_VALUE;
Drawable drawable = null;
- if (previewImage != 0) {
- drawable = mPackageManager.getDrawable(packageName, previewImage, null);
+ if (info.previewImage != 0) {
+ drawable = mManager.loadPreview(info);
if (drawable != null) {
drawable = mutateOnMainThread(drawable);
} else {
Log.w(TAG, "Can't load widget preview drawable 0x" +
- Integer.toHexString(previewImage) + " for provider: " + provider);
+ Integer.toHexString(info.previewImage) + " for provider: " + info.provider);
}
}
@@ -562,21 +560,16 @@
c.setBitmap(null);
// Draw the icon in the top left corner
- int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage);
+ int minOffset = (int) (mAppIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE);
int smallestSide = Math.min(previewWidth, previewHeight);
float iconScale = Math.min((float) smallestSide
/ (mAppIconSize + 2 * minOffset), 1f);
try {
- Drawable icon = null;
- int hoffset =
- (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2);
- int yoffset =
- (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2);
- if (iconId > 0) {
- icon = mIconCache.getFullResIcon(packageName, iconId);
- }
+ Drawable icon = mManager.loadIcon(info, mIconCache);
if (icon != null) {
+ int hoffset = (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2);
+ int yoffset = (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2);
icon = mutateOnMainThread(icon);
renderDrawableToBitmap(icon, defaultPreview, hoffset,
yoffset, (int) (mAppIconSize * iconScale),
@@ -627,7 +620,7 @@
c.drawBitmap(defaultPreview, src, dest, p);
c.setBitmap(null);
}
- return preview;
+ return mManager.getBadgeBitmap(info, preview);
}
private Bitmap generateShortcutPreview(
@@ -685,18 +678,10 @@
return preview;
}
-
- public static void renderDrawableToBitmap(
- Drawable d, Bitmap bitmap, int x, int y, int w, int h) {
- renderDrawableToBitmap(d, bitmap, x, y, w, h, 1f);
- }
-
private static void renderDrawableToBitmap(
- Drawable d, Bitmap bitmap, int x, int y, int w, int h,
- float scale) {
+ Drawable d, Bitmap bitmap, int x, int y, int w, int h) {
if (bitmap != null) {
Canvas c = new Canvas(bitmap);
- c.scale(scale, scale);
Rect oldBounds = d.copyBounds();
d.setBounds(x, y, x + w, y + h);
d.draw(c);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 733923d..ace5e84 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -27,7 +27,6 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.WallpaperManager;
-import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
@@ -47,9 +46,7 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
-import android.os.Handler.Callback;
import android.os.IBinder;
-import android.os.Message;
import android.os.Parcelable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
@@ -76,9 +73,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
/**
* The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -212,10 +207,10 @@
private HolographicOutlineHelper mOutlineHelper;
private Bitmap mDragOutline = null;
- private final Rect mTempRect = new Rect();
+ private static final Rect sTempRect = new Rect();
private final int[] mTempXY = new int[2];
private int[] mTempVisiblePagesRange = new int[2];
- private boolean mOverscrollTransformsSet;
+ private boolean mOverscrollEffectSet;
public static final int DRAG_BITMAP_PADDING = 2;
private boolean mWorkspaceFadeInAdjacentScreens;
@@ -241,6 +236,8 @@
private DropTarget.DragEnforcer mDragEnforcer;
private float mMaxDistanceForFolderCreation;
+ private final Canvas mCanvas = new Canvas();
+
// Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
private float mXDown;
private float mYDown;
@@ -281,6 +278,8 @@
private int mLastChildCount = -1;
private float mTransitionProgress;
+ float mOverScrollEffect = 0f;
+
private Runnable mDeferredAction;
private boolean mDeferDropAfterUninstall;
private boolean mUninstallSuccessful;
@@ -583,6 +582,7 @@
CellLayout customScreen = (CellLayout)
mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);
customScreen.disableBackground();
+ customScreen.disableDragTarget();
mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);
mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID);
@@ -1112,6 +1112,17 @@
return super.onInterceptTouchEvent(ev);
}
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ // Ignore pointer scroll events if the custom content doesn't allow scrolling.
+ if ((getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID)
+ && (mCustomContentCallbacks != null)
+ && !mCustomContentCallbacks.isScrollingAllowed()) {
+ return false;
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
protected void reinflateWidgetsIfNecessary() {
final int clCount = getChildCount();
for (int i = 0; i < clCount; i++) {
@@ -1581,7 +1592,7 @@
private void updatePageAlphaValues(int screenCenter) {
boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
if (mWorkspaceFadeInAdjacentScreens &&
- mState == State.NORMAL &&
+ !workspaceInModalState() &&
!mIsSwitchingState &&
!isInOverscroll) {
for (int i = numCustomPages(); i < getChildCount(); i++) {
@@ -1590,6 +1601,7 @@
float scrollProgress = getScrollProgress(screenCenter, child, i);
float alpha = 1 - Math.abs(scrollProgress);
child.getShortcutsAndWidgets().setAlpha(alpha);
+ //child.setBackgroundAlphaMultiplier(1 - alpha);
}
}
}
@@ -1683,14 +1695,10 @@
updateStateForCustomContent(screenCenter);
enableHwLayersOnVisiblePages();
- boolean shouldOverScroll = (mOverScrollX < 0 && (!hasCustomContent() || isLayoutRtl())) ||
- (mOverScrollX > mMaxScrollX && (!hasCustomContent() || !isLayoutRtl()));
+ boolean shouldOverScroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
if (shouldOverScroll) {
int index = 0;
- float pivotX = 0f;
- final float leftBiasedPivot = 0.25f;
- final float rightBiasedPivot = 0.75f;
final int lowerIndex = 0;
final int upperIndex = getChildCount() - 1;
@@ -1698,25 +1706,29 @@
index = (!isRtl && isLeftPage) || (isRtl && !isLeftPage) ? lowerIndex : upperIndex;
CellLayout cl = (CellLayout) getChildAt(index);
- float scrollProgress = getScrollProgress(screenCenter, cl, index);
- cl.setOverScrollAmount(Math.abs(scrollProgress), isLeftPage);
+ float effect = Math.abs(mOverScrollEffect);
+ cl.setOverScrollAmount(Math.abs(effect), isLeftPage);
- if (!mOverscrollTransformsSet) {
- mOverscrollTransformsSet = true;
- cl.setOverscrollTransformsDirty(true);
- }
+ mOverscrollEffectSet = true;
} else {
- if (mOverscrollTransformsSet && getChildCount() > 0) {
- mOverscrollTransformsSet = false;
- ((CellLayout) getChildAt(0)).resetOverscrollTransforms();
- ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms();
+ if (mOverscrollEffectSet && getChildCount() > 0) {
+ mOverscrollEffectSet = false;
+ ((CellLayout) getChildAt(0)).setOverScrollAmount(0, false);
+ ((CellLayout) getChildAt(getChildCount() - 1)).setOverScrollAmount(0, false);
}
}
}
@Override
protected void overScroll(float amount) {
- acceleratedOverScroll(amount);
+ boolean shouldOverScroll = (amount < 0 && (!hasCustomContent() || isLayoutRtl())) ||
+ (amount > 0 && (!hasCustomContent() || !isLayoutRtl()));
+ if (shouldOverScroll) {
+ dampedOverScroll(amount);
+ mOverScrollEffect = acceleratedOverFactor(amount);
+ } else {
+ mOverScrollEffect = 0;
+ }
}
protected void onAttachedToWindow() {
@@ -1979,14 +1991,7 @@
* appearance).
*
*/
- public void onDragStartedWithItem(View v) {
- final Canvas canvas = new Canvas();
-
- // The outline is used to visualize where the item will land if dropped
- mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);
- }
-
- private Rect getDrawableBounds(Drawable d) {
+ private static Rect getDrawableBounds(Drawable d) {
Rect bounds = new Rect();
d.copyBounds(bounds);
if (bounds.width() == 0 || bounds.height() == 0) {
@@ -2002,8 +2007,6 @@
}
public void onExternalDragStartedWithItem(View v) {
- final Canvas canvas = new Canvas();
-
// Compose a drag bitmap with the view scaled to the icon size
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
@@ -2023,22 +2026,19 @@
// Compose the bitmap to create the icon from
Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight,
Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(b);
- drawDragView(v, c, 0);
- c.setBitmap(null);
+ mCanvas.setBitmap(b);
+ drawDragView(v, mCanvas, 0);
+ mCanvas.setBitmap(null);
// The outline is used to visualize where the item will land if dropped
- mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, iconSize, iconSize, true);
+ mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true);
}
public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
- final Canvas canvas = new Canvas();
-
int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
// The outline is used to visualize where the item will land if dropped
- mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],
- size[1], clipAlpha);
+ mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);
}
public void exitWidgetResizeMode() {
@@ -2536,8 +2536,8 @@
* @param destCanvas the canvas to draw on
* @param padding the horizontal and vertical padding to use when drawing
*/
- private void drawDragView(View v, Canvas destCanvas, int padding) {
- final Rect clipRect = mTempRect;
+ private static void drawDragView(View v, Canvas destCanvas, int padding) {
+ final Rect clipRect = sTempRect;
v.getDrawingRect(clipRect);
boolean textVisible = false;
@@ -2576,7 +2576,7 @@
* @param expectedPadding padding to add to the drag view. If a different padding was used
* its value will be changed
*/
- public Bitmap createDragBitmap(View v, Canvas canvas, AtomicInteger expectedPadding) {
+ public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) {
Bitmap b;
int padding = expectedPadding.get();
@@ -2591,9 +2591,9 @@
v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
}
- canvas.setBitmap(b);
- drawDragView(v, canvas, padding);
- canvas.setBitmap(null);
+ mCanvas.setBitmap(b);
+ drawDragView(v, mCanvas, padding);
+ mCanvas.setBitmap(null);
return b;
}
@@ -2602,15 +2602,15 @@
* Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
* Responsibility for the bitmap is transferred to the caller.
*/
- private Bitmap createDragOutline(View v, Canvas canvas, int padding) {
+ private Bitmap createDragOutline(View v, int padding) {
final int outlineColor = getResources().getColor(R.color.outline_color);
final Bitmap b = Bitmap.createBitmap(
v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
- canvas.setBitmap(b);
- drawDragView(v, canvas, padding);
- mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
- canvas.setBitmap(null);
+ mCanvas.setBitmap(b);
+ drawDragView(v, mCanvas, padding);
+ mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor);
+ mCanvas.setBitmap(null);
return b;
}
@@ -2618,11 +2618,11 @@
* Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
* Responsibility for the bitmap is transferred to the caller.
*/
- private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,
+ private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h,
boolean clipAlpha) {
final int outlineColor = getResources().getColor(R.color.outline_color);
final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
- canvas.setBitmap(b);
+ mCanvas.setBitmap(b);
Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
@@ -2634,10 +2634,10 @@
// center the image
dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
- canvas.drawBitmap(orig, src, dst, null);
- mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,
+ mCanvas.drawBitmap(orig, src, dst, null);
+ mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor,
clipAlpha);
- canvas.setBitmap(null);
+ mCanvas.setBitmap(null);
return b;
}
@@ -2655,21 +2655,20 @@
CellLayout layout = (CellLayout) child.getParent().getParent();
layout.prepareChildForDrag(child);
- child.clearFocus();
- child.setPressed(false);
-
- final Canvas canvas = new Canvas();
-
- // The outline is used to visualize where the item will land if dropped
- mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
beginDragShared(child, this);
}
public void beginDragShared(View child, DragSource source) {
+ child.clearFocus();
+ child.setPressed(false);
+
+ // The outline is used to visualize where the item will land if dropped
+ mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING);
+
mLauncher.onDragStarted(child);
// The drag bitmap follows the touch point around on the screen
AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);
- final Bitmap b = createDragBitmap(child, new Canvas(), padding);
+ final Bitmap b = createDragBitmap(child, padding);
final int bmpWidth = b.getWidth();
final int bmpHeight = b.getHeight();
@@ -2683,7 +2682,7 @@
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
Point dragVisualizeOffset = null;
Rect dragRect = null;
- if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {
+ if (child instanceof BubbleTextView) {
int iconSize = grid.iconSizePx;
int top = child.getPaddingTop();
int left = (bmpWidth - iconSize) / 2;
@@ -2702,7 +2701,7 @@
// Clear the pressed state if necessary
if (child instanceof BubbleTextView) {
BubbleTextView icon = (BubbleTextView) child;
- icon.clearPressedOrFocusedBackground();
+ icon.clearPressedBackground();
} else if (child instanceof FolderIcon) {
// The folder cling isn't flexible enough to be shown in non-default workspace positions
// Also if they are dragging it a folder, we assume they don't need to see the cling.
@@ -2737,14 +2736,14 @@
// Compose a new drag bitmap that is of the icon size
AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);
- final Bitmap tmpB = createDragBitmap(child, new Canvas(), padding);
+ final Bitmap tmpB = createDragBitmap(child, padding);
Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
Paint p = new Paint();
p.setFilterBitmap(true);
- Canvas c = new Canvas(b);
- c.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()),
+ mCanvas.setBitmap(b);
+ mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()),
new Rect(0, 0, iconSize, iconSize), p);
- c.setBitmap(null);
+ mCanvas.setBitmap(null);
// Find the child's location on the screen
int bmpWidth = tmpB.getWidth();
@@ -3241,10 +3240,8 @@
setCurrentDropLayout(layout);
setCurrentDragOverlappingLayout(layout);
- // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we
- // don't need to show the outlines
- if (LauncherAppState.getInstance().isScreenLarge()) {
- showOutlines();
+ if (!workspaceInModalState()) {
+ mLauncher.getDragLayer().showPageHints();
}
}
@@ -3319,6 +3316,7 @@
if (!mIsPageMoving) {
hideOutlines();
}
+ mLauncher.getDragLayer().hidePageHints();
}
void setCurrentDropLayout(CellLayout layout) {
@@ -4019,12 +4017,12 @@
int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);
Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],
Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(b);
+ mCanvas.setBitmap(b);
layout.measure(width, height);
layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
- layout.draw(c);
- c.setBitmap(null);
+ layout.draw(mCanvas);
+ mCanvas.setBitmap(null);
layout.setVisibility(visibility);
return b;
}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
new file mode 100644
index 0000000..57fac7f
--- /dev/null
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.app.Activity;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.Utilities;
+
+import java.util.List;
+
+public abstract class AppWidgetManagerCompat {
+
+ private static final Object sInstanceLock = new Object();
+ private static AppWidgetManagerCompat sInstance;
+
+
+ public static AppWidgetManagerCompat getInstance(Context context) {
+ synchronized (sInstanceLock) {
+ // TODO change this to use api version once L gets an API number.
+ if (sInstance == null) {
+ if (Utilities.isLmp()) {
+ sInstance = new AppWidgetManagerCompatVL(context);
+ } else {
+ sInstance = new AppWidgetManagerCompatV16(context);
+ }
+ }
+ return sInstance;
+ }
+ }
+
+ final AppWidgetManager mAppWidgetManager;
+ final Context mContext;
+
+ AppWidgetManagerCompat(Context context) {
+ mContext = context;
+ mAppWidgetManager = AppWidgetManager.getInstance(context);
+ }
+
+ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+ return mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ }
+
+ public abstract List<AppWidgetProviderInfo> getAllProviders();
+
+ public abstract String loadLabel(AppWidgetProviderInfo info);
+
+ public abstract boolean bindAppWidgetIdIfAllowed(
+ int appWidgetId, AppWidgetProviderInfo info, Bundle options);
+
+ public abstract UserHandleCompat getUser(AppWidgetProviderInfo info);
+
+ public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId,
+ Activity activity, AppWidgetHost host, int requestCode);
+
+ public abstract Drawable loadPreview(AppWidgetProviderInfo info);
+
+ public abstract Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache);
+
+ public abstract Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap);
+
+}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
new file mode 100644
index 0000000..f599f43
--- /dev/null
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.app.Activity;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.Utilities;
+
+import java.util.List;
+
+class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat {
+
+ AppWidgetManagerCompatV16(Context context) {
+ super(context);
+ }
+
+ @Override
+ public List<AppWidgetProviderInfo> getAllProviders() {
+ return mAppWidgetManager.getInstalledProviders();
+ }
+
+ @Override
+ public String loadLabel(AppWidgetProviderInfo info) {
+ return info.label.trim();
+ }
+
+ @Override
+ public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
+ Bundle options) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider);
+ } else {
+ return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider, options);
+ }
+ }
+
+ @Override
+ public UserHandleCompat getUser(AppWidgetProviderInfo info) {
+ return UserHandleCompat.myUserHandle();
+ }
+
+ @Override
+ public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity,
+ AppWidgetHost host, int requestCode) {
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
+ intent.setComponent(info.configure);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
+ Utilities.startActivityForResultSafely(activity, intent, requestCode);
+ }
+
+ @Override
+ public Drawable loadPreview(AppWidgetProviderInfo info) {
+ return mContext.getPackageManager().getDrawable(
+ info.provider.getPackageName(), info.previewImage, null);
+ }
+
+ @Override
+ public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) {
+ return cache.getFullResIcon(info.provider.getPackageName(), info.icon);
+ }
+
+ @Override
+ public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) {
+ return bitmap;
+ }
+}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
new file mode 100644
index 0000000..535c74b
--- /dev/null
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@TargetApi(Build.VERSION_CODES.L)
+class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
+
+ private final UserManager mUserManager;
+ private final PackageManager mPm;
+
+ AppWidgetManagerCompatVL(Context context) {
+ super(context);
+ mPm = context.getPackageManager();
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ }
+
+ @Override
+ public List<AppWidgetProviderInfo> getAllProviders() {
+ ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>();
+ for (UserHandle user : mUserManager.getUserProfiles()) {
+ providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user));
+ }
+ return providers;
+ }
+
+ @Override
+ public String loadLabel(AppWidgetProviderInfo info) {
+ return info.loadLabel(mPm);
+ }
+
+ @Override
+ public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
+ Bundle options) {
+ return mAppWidgetManager.bindAppWidgetIdIfAllowed(
+ appWidgetId, info.getProfile(), info.provider, options);
+ }
+
+ @Override
+ public UserHandleCompat getUser(AppWidgetProviderInfo info) {
+ return UserHandleCompat.fromUser(info.getProfile());
+ }
+
+ @Override
+ public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity,
+ AppWidgetHost host, int requestCode) {
+ try {
+ host.startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, null);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ } catch (SecurityException e) {
+ Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public Drawable loadPreview(AppWidgetProviderInfo info) {
+ return info.loadPreviewImage(mContext, 0);
+ }
+
+ @Override
+ public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) {
+ return info.loadIcon(mContext, cache.getFullResIconDpi());
+ }
+
+ @Override
+ public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) {
+ if (info.getProfile().equals(android.os.Process.myUserHandle())) {
+ return bitmap;
+ }
+
+ // Add a user badge in the bottom right of the image.
+ final Resources res = mContext.getResources();
+ final int badgeSize = res.getDimensionPixelSize(R.dimen.profile_badge_size);
+ final int badgeMargin = res.getDimensionPixelSize(R.dimen.profile_badge_margin);
+ final Rect badgeLocation = new Rect(0, 0, badgeSize, badgeSize);
+
+ final int top = bitmap.getHeight() - badgeSize - badgeMargin;
+ if (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ badgeLocation.offset(badgeMargin, top);
+ } else {
+ badgeLocation.offset(bitmap.getWidth() - badgeSize - badgeMargin, top);
+ }
+
+ UserManager userManager = (UserManager) mContext.getSystemService(
+ Context.USER_SERVICE);
+
+ Drawable drawable = userManager.getBadgedDrawableForUser(new BitmapDrawable(res, bitmap),
+ info.getProfile(), badgeLocation, 0);
+
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ }
+
+ bitmap.eraseColor(Color.TRANSPARENT);
+ Canvas c = new Canvas(bitmap);
+ drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ drawable.draw(c);
+ c.setBitmap(null);
+ return bitmap;
+ }
+}
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 26e1b7c..c78ab99 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -17,9 +17,9 @@
package com.android.launcher3.compat;
import android.content.Context;
-import android.content.pm.InstallSessionInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionCallback;
+import android.content.pm.PackageInstaller.SessionInfo;
import android.util.Log;
import android.util.SparseArray;
@@ -33,7 +33,7 @@
private static final String TAG = "PackageInstallerCompatVL";
private static final boolean DEBUG = false;
- private final SparseArray<InstallSessionInfo> mPendingReplays = new SparseArray<InstallSessionInfo>();
+ private final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>();
private final PackageInstaller mInstaller;
private boolean mResumed;
@@ -47,7 +47,7 @@
mInstaller.addSessionCallback(mCallback);
// On start, send updates for all active sessions
- for (InstallSessionInfo info : mInstaller.getAllSessions()) {
+ for (SessionInfo info : mInstaller.getAllSessions()) {
mPendingReplays.append(info.getSessionId(), info);
}
}
@@ -102,7 +102,7 @@
updates.add(newInfo);
}
for (int i = mPendingReplays.size() - 1; i > 0; i--) {
- InstallSessionInfo session = mPendingReplays.valueAt(i);
+ SessionInfo session = mPendingReplays.valueAt(i);
if (session.getAppPackageName() != null) {
updates.add(new PackageInstallInfo(session.getAppPackageName(),
ShortcutInfo.PACKAGE_STATE_INSTALLING,
@@ -119,7 +119,7 @@
@Override
public void onCreated(int sessionId) {
- InstallSessionInfo session = mInstaller.getSessionInfo(sessionId);
+ SessionInfo session = mInstaller.getSessionInfo(sessionId);
if (session != null) {
mPendingReplays.put(sessionId, session);
replayUpdates(null);
@@ -129,7 +129,7 @@
@Override
public void onFinished(int sessionId, boolean success) {
mPendingReplays.remove(sessionId);
- InstallSessionInfo session = mInstaller.getSessionInfo(sessionId);
+ SessionInfo session = mInstaller.getSessionInfo(sessionId);
if ((session != null) && (session.getAppPackageName() != null)) {
// Replay all updates with a one time update for this installed package. No
// need to store this record for future updates, as the app list will get
@@ -142,7 +142,7 @@
@Override
public void onProgressChanged(int sessionId, float progress) {
- InstallSessionInfo session = mInstaller.getSessionInfo(sessionId);
+ SessionInfo session = mInstaller.getSessionInfo(sessionId);
if (session != null) {
mPendingReplays.put(sessionId, session);
replayUpdates(null);