summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTyson Miller <tmiller@cyngn.com>2015-11-10 08:59:15 -0800
committerArtem Shvadskiy <ashvadskiy@cyngn.com>2016-01-13 12:33:59 -0800
commit1792a57516c52145db6dcadb247bce452410b98c (patch)
tree86656bb6c7b3119cf4c70e07303740ce091d980b
parent892fafe5b66d33746fe72bf51ed015772646a223 (diff)
downloadandroid_packages_apps_Trebuchet-1792a57516c52145db6dcadb247bce452410b98c.tar.gz
android_packages_apps_Trebuchet-1792a57516c52145db6dcadb247bce452410b98c.tar.bz2
android_packages_apps_Trebuchet-1792a57516c52145db6dcadb247bce452410b98c.zip
Merge Remote Folder into mainline.
Patch 1: Squash. Patch 2: Remove obsolete code. Patch 3: Clean rebase. Patch 4: Fix commit message. Change-Id: Ie9c634d7d2f0824b3b1de84e8f0af5442e5511cc
-rw-r--r--Android.mk9
-rw-r--r--AndroidManifest.xml1
-rw-r--r--RemoteFolder/Android.mk1
-rw-r--r--RemoteFolder/src/com/android/launcher3/RemoteFolderManager.java97
-rw-r--r--proguard.flags39
-rw-r--r--res/drawable/download_badge.pngbin0 -> 2711 bytes
-rw-r--r--res/drawable/triangle_icon.pngbin0 -> 12557 bytes
-rw-r--r--res/layout/app_drawer_item.xml59
-rw-r--r--res/layout/app_drawer_item_custom_header.xml3
-rw-r--r--res/layout/remote_folder.xml4
-rw-r--r--res/layout/user_folder.xml15
-rw-r--r--res/values/colors.xml3
-rw-r--r--res/values/dimens.xml18
-rw-r--r--res/values/preferences_defaults.xml1
-rw-r--r--src/com/android/launcher3/AppDrawerListAdapter.java350
-rw-r--r--src/com/android/launcher3/AppDrawerScrubberSections.java11
-rw-r--r--src/com/android/launcher3/AppInfo.java41
-rw-r--r--src/com/android/launcher3/AutoFitTextView.java8
-rw-r--r--src/com/android/launcher3/BubbleTextView.java22
-rw-r--r--src/com/android/launcher3/DeleteDropTarget.java12
-rw-r--r--src/com/android/launcher3/Folder.java173
-rw-r--r--src/com/android/launcher3/FolderIcon.java53
-rw-r--r--src/com/android/launcher3/FolderInfo.java59
-rw-r--r--src/com/android/launcher3/ItemInfo.java7
-rw-r--r--src/com/android/launcher3/Launcher.java50
-rw-r--r--src/com/android/launcher3/LauncherApplication.java2
-rw-r--r--src/com/android/launcher3/LauncherModel.java15
-rw-r--r--src/com/android/launcher3/LauncherProvider.java20
-rw-r--r--src/com/android/launcher3/LauncherSettings.java4
-rw-r--r--src/com/android/launcher3/OverviewSettingsPanel.java48
-rw-r--r--src/com/android/launcher3/ShortcutInfo.java10
-rw-r--r--src/com/android/launcher3/Utilities.java15
-rw-r--r--src/com/android/launcher3/Workspace.java12
-rw-r--r--src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java19
-rw-r--r--src/com/android/launcher3/settings/SettingsProvider.java1
-rw-r--r--src/com/android/launcher3/stats/LauncherStats.java35
-rw-r--r--src/com/android/launcher3/stats/internal/model/TrackingEvent.java8
37 files changed, 824 insertions, 401 deletions
diff --git a/Android.mk b/Android.mk
index af967ac5a..04d4e4e9a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -27,6 +27,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13 \
android-support-v7-recyclerview \
guava
+
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-java-files-under, WallpaperPicker/src) \
$(call all-renderscript-files-under, src) \
@@ -49,10 +50,15 @@ LOCAL_AAPT_FLAGS += --rename-manifest-package com.cyanogenmod.trebuchet
LOCAL_OVERRIDES_PACKAGES := Launcher3
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_PROGUARD_ENABLED := full
+
+REMOTE_FOLDER_UPDATER ?= $(LOCAL_PATH)/RemoteFolder
+include $(REMOTE_FOLDER_UPDATER)/Android.mk
include $(BUILD_PACKAGE)
+include $(CLEAR_VARS)
+include $(BUILD_MULTI_PREBUILT)
#
# Protocol Buffer Debug Utility in Java
@@ -72,6 +78,7 @@ LOCAL_JAR_MANIFEST := util/etc/manifest.txt
include $(BUILD_HOST_JAVA_LIBRARY)
+
#
# Protocol Buffer Debug Utility Wrapper Script
#
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 70da93e2a..df64f92de 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -68,6 +68,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
<uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
diff --git a/RemoteFolder/Android.mk b/RemoteFolder/Android.mk
new file mode 100644
index 000000000..2a7441345
--- /dev/null
+++ b/RemoteFolder/Android.mk
@@ -0,0 +1 @@
+LOCAL_SRC_FILES += $(call all-java-files-under, RemoteFolder/src)
diff --git a/RemoteFolder/src/com/android/launcher3/RemoteFolderManager.java b/RemoteFolder/src/com/android/launcher3/RemoteFolderManager.java
new file mode 100644
index 000000000..b3a147c19
--- /dev/null
+++ b/RemoteFolder/src/com/android/launcher3/RemoteFolderManager.java
@@ -0,0 +1,97 @@
+package com.android.launcher3;
+
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+
+/**
+ * Manages adding and removing the remote folder from the workspace.
+ */
+public class RemoteFolderManager {
+
+ public RemoteFolderManager(final Launcher launcher) { }
+
+ /**
+ * Create a remote folder view.
+ * @param icon folder icon view on the workspace.
+ * @return a view for the remote folder.
+ */
+ public Folder createRemoteFolder(final FolderIcon icon, ViewGroup root) { return null; }
+
+ /**
+ * Get a drawable for the supplied item in the folder icon preview.
+ * @param items list of views in the folder.
+ * @param position index of icon to retreive.
+ * @return an icon to draw in the folder preview.
+ */
+ public Drawable getFolderIconDrawable(final ArrayList<View> items,
+ final int position) { return null; }
+
+ /**
+ * Called when Launcher finishes binding items from the model.
+ */
+ public void bindFinished() { }
+
+ /**
+ * Called when the setting for remote folder is updated.
+ * @param newValue the new setting for remote folder
+ */
+ public void onSettingChanged(final boolean newValue) { }
+
+ /**
+ * Called when the remote folder is dropped into the delete area on the workspace.
+ */
+ public void onFolderDeleted() { }
+
+ /**
+ * Called when the app drawer is opened.
+ */
+ public void onAppDrawerOpened() { }
+
+ /**
+ * Called when new apps are added to launcher.
+ * @param apps list of added apps.
+ */
+ public void onBindAddApps(ArrayList<AppInfo> apps) { }
+
+ /**
+ * Called when launcher loads apps and applies them to the drawer.
+ */
+ public void onSetApps() { }
+
+ /**
+ * Called when the info icon is clicked
+ */
+ public void onInfoIconClicked() { }
+
+ /**
+ * Change the appearance of FolderIcon for our RemoteFolder by adding a badge
+ * @param icon the FolderIcon to update
+ * @return a FolderIcon with an added ImageView
+ */
+ public static FolderIcon addBadgeToFolderIcon(FolderIcon icon) {
+ return icon;
+ }
+
+ /**
+ * Called when the view holder is created for the remote header.
+ * @param holder remote view holder.
+ */
+ public void onCreateViewHolder(final AppDrawerListAdapter.ViewHolder holder) { }
+ /**
+ * Called when the view holder is bound for the remote header.
+ * @param holder remote view holder.
+ * @param indexedInfo header info.
+ */
+ public void onBindViewHolder(final AppDrawerListAdapter.ViewHolder holder,
+ final AppDrawerListAdapter.AppItemIndexedInfo indexedInfo) { }
+
+ /**
+ * Get the String to be used for the RemoteFolder name and its corresponding Settings option
+ * @return the name RemoteFolder and its Setting option should use
+ */
+ public static String getFeatureTitle(Resources res) { return null; }
+}
diff --git a/proguard.flags b/proguard.flags
index 0b28c0ef4..440477b26 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -1,3 +1,8 @@
+-keepattributes SourceFile,LineNumberTable,InnerClasses
+-keep class com.inmobi.** { *; }
+-dontwarn com.inmobi.**
+-dontwarn com.google.android.gms**
+
-keep class com.android.launcher3.Launcher {
public void previousScreen(android.view.View);
public void nextScreen(android.view.View);
@@ -57,3 +62,37 @@
public float getAnimationProgress();
public void setAnimationProgress(float);
}
+
+-keep class * extends java.util.ListResourceBundle {
+ protected Object[][] getContents();
+}
+
+-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
+ public static final *** NULL;
+}
+
+-keepnames @com.google.android.gms.common.annotation.KeepName class *
+-keepclassmembernames class * {
+ @com.google.android.gms.common.annotation.KeepName *;
+}
+
+-keepnames class * implements android.os.Parcelable {
+ public static final ** CREATOR;
+}
+
+-keep class android.content.res.** { *; }
+-dontwarn android.content.res.*
+
+-keep class android.view.inputmethod.** { *; }
+-dontwarn android.view.inputmethod.*
+
+-keep class com.google.android.gms.common.api.GoogleApiClient { public *; }
+-keep class com.google.android.gms.common.api.GoogleApiClient$* {public *;}
+-keep class com.google.android.gms.location.LocationServices {public *;}
+-keep class com.google.android.gms.location.FusedLocationProviderApi {public *;}
+-keep class com.google.android.gms.location.ActivityRecognition {public *;}
+-keep class com.google.android.gms.location.ActivityRecognitionApi {public *;}
+-keep class com.google.android.gms.location.ActivityRecognitionResult {public *;}
+-keep class com.google.android.gms.location.DetectedActivity {public *;}
+-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient{public *;}
+-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info{public *;} \ No newline at end of file
diff --git a/res/drawable/download_badge.png b/res/drawable/download_badge.png
new file mode 100644
index 000000000..fad49b65f
--- /dev/null
+++ b/res/drawable/download_badge.png
Binary files differ
diff --git a/res/drawable/triangle_icon.png b/res/drawable/triangle_icon.png
new file mode 100644
index 000000000..209cf851e
--- /dev/null
+++ b/res/drawable/triangle_icon.png
Binary files differ
diff --git a/res/layout/app_drawer_item.xml b/res/layout/app_drawer_item.xml
index 7322b73e3..03ca60a00 100644
--- a/res/layout/app_drawer_item.xml
+++ b/res/layout/app_drawer_item.xml
@@ -15,57 +15,62 @@
limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:autofit="http://schemas.android.com/apk/res-auto"
- android:splitMotionEvents="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ xmlns:autofit="http://schemas.android.com/apk/res-auto"
+ android:splitMotionEvents="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <!-- Layout in back to front render order -->
<View
android:id="@+id/fading_background_back"
android:alpha="0"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:layout_alignTop="@+id/drawer_item_flow"
+ android:layout_alignParentTop="true"
android:layout_alignBottom="@+id/drawer_item_flow"
android:background="@color/app_drawer_drag_background" />
- <!-- Layout in back to front render order -->
+ <include
+ android:id="@+id/custom_header_layout"
+ layout="@layout/app_drawer_item_custom_header" />
+
<LinearLayout
- android:id="@+id/drawer_item_flow"
- android:layout_alignParentEnd="true"
- android:layout_toEndOf="@+id/drawer_item_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal" />
+ android:id="@+id/drawer_item_flow"
+ android:layout_alignParentEnd="true"
+ android:layout_toEndOf="@+id/drawer_item_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/custom_header_layout"
+ android:orientation="horizontal" />
<View
android:id="@+id/fading_background_front"
android:alpha="0"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:layout_alignTop="@id/drawer_item_flow"
+ android:layout_alignParentTop="true"
android:layout_alignBottom="@id/drawer_item_flow"
android:background="@color/app_drawer_drag_background" />
<com.android.launcher3.AutoFitTextView
- android:id="@+id/drawer_item_title"
- android:layout_width="@dimen/app_drawer_char_width"
- android:layout_height="fill_parent"
- android:layout_marginTop="6dp"
- android:layout_marginBottom="24dp"
- android:layout_marginStart="6dp"
- android:layout_alignTop="@id/drawer_item_flow"
+ android:id="@id/drawer_item_title"
+ android:layout_width="@dimen/drawer_header_text_char_width"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/drawer_header_text_margin_top"
+ android:layout_marginBottom="@dimen/drawer_header_text_margin_bottom"
+ android:layout_marginStart="@dimen/drawer_header_text_margin_start"
+ android:layout_alignTop="@id/custom_header_layout"
+ android:layout_alignWithParentIfMissing="true"
android:layout_alignBottom="@id/drawer_item_flow"
- android:layout_centerVertical="true"
android:includeFontPadding="false"
android:gravity="center"
android:singleLine="true"
- autofit:minTextSize="8sp"
- android:textSize="24sp"
- android:layout_gravity="center"
+ autofit:minTextSize="@dimen/drawer_header_text_min_text_size"
+ android:textSize="@dimen/drawer_header_text_size"
android:fontFamily="sans-serif-light"
android:textColor="@android:color/white"
- android:shadowRadius="4.0"
- android:shadowDy="2"
- android:shadowColor="#b0000000"/>
+ android:shadowRadius="@dimen/drawer_header_text_shadow_radius"
+ android:shadowDy="@dimen/drawer_header_text_shadow_dy"
+ android:shadowColor="@color/drawer_header_text_shadow"/>
</RelativeLayout>
diff --git a/res/layout/app_drawer_item_custom_header.xml b/res/layout/app_drawer_item_custom_header.xml
new file mode 100644
index 000000000..14c171ee6
--- /dev/null
+++ b/res/layout/app_drawer_item_custom_header.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+</merge> \ No newline at end of file
diff --git a/res/layout/remote_folder.xml b/res/layout/remote_folder.xml
new file mode 100644
index 000000000..49d47292d
--- /dev/null
+++ b/res/layout/remote_folder.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+</merge> \ No newline at end of file
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index d1a7536a3..a25710ec8 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -23,12 +23,17 @@
android:paddingStart="@dimen/folder_preview_padding"
android:paddingEnd="@dimen/folder_preview_padding"
android:paddingBottom="@dimen/folder_preview_padding"
- android:layout_gravity="center"
+ android:layout_margin="@dimen/folder_margin"
+ android:layout_gravity="bottom|center_horizontal"
android:background="@drawable/folder_bg">
+ <include layout="@layout/remote_folder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
<ScrollView
android:id="@+id/scroll_view"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
<com.android.launcher3.CellLayout
@@ -41,7 +46,7 @@
<RelativeLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:id="@+id/folder_name_lock_container">
<ImageView
@@ -50,7 +55,6 @@
android:layout_height="@dimen/folder_lock_icon"
android:padding="@dimen/folder_name_padding"
android:layout_alignParentEnd="true"
- android:layout_alignParentBottom="true"
android:src="@drawable/folder_unlocked" />
<com.android.launcher3.FolderEditText
@@ -73,8 +77,7 @@
android:textSize="18sp"
android:layout_toStartOf="@id/folder_lock"
android:layout_alignTop="@id/folder_lock"
- android:layout_alignParentStart="true"
- android:layout_alignParentBottom="true"/>
+ android:layout_alignParentStart="true"/>
</RelativeLayout>
</com.android.launcher3.Folder>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 5c04aa3e4..55f17a394 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -48,13 +48,14 @@
<color name="dynamic_grid_preview_background">#FFFFFFFF</color>
<color name="dynamic_grid_preview_foreground">#FF000000</color>
+ <!-- App drawer -->
<color name="app_drawer_background">#76000000</color>
<color name="app_drawer_drag_background">#bf14191e</color>
<color name="app_scrubber_highlight_color">@android:color/white</color>
<color name="app_scrubber_gray_color">@android:color/darker_gray</color>
<color name="scrubber_background">#CC14191E</color>
- <color name="aftv_shadowColor">#b0000000</color>
+ <color name="drawer_header_text_shadow">#b0000000</color>
<color name="folder_background">#141a1e</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b92eae20e..a100beb58 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -105,6 +105,7 @@
<dimen name="folder_lock_margin">6dp</dimen>
<dimen name="folder_name_padding">10dp</dimen>
<dimen name="folder_lock_icon">48dp</dimen>
+ <dimen name="folder_margin">24dp</dimen>
<!-- Folder icon dimens -->
<dimen name="folder_icon">64dp</dimen>
@@ -131,14 +132,15 @@
<dimen name="app_drawer_scrubber_padding">20dp</dimen>
- <!-- App Drawer Item -->
- <dimen name="app_drawer_char_width">27dp</dimen>
- <dimen name="container_paddingStart">6dp</dimen>
- <dimen name="container_paddingEnd">6dp</dimen>
- <dimen name="aftv_width">32dp</dimen>
- <dimen name="aftv_marginTop">10dp</dimen>
- <dimen name="aftv_minTextSize">8sp</dimen>
- <dimen name="aftv_textSize">24sp</dimen>
+<!-- App Drawer Item -->
+ <dimen name="drawer_header_text_char_width">27dp</dimen>
+ <dimen name="drawer_header_text_min_text_size">8sp</dimen>
+ <dimen name="drawer_header_text_margin_bottom">24dp</dimen>
+ <dimen name="drawer_header_text_margin_start">6dp</dimen>
+ <dimen name="drawer_header_text_margin_top">6dp</dimen>
+ <dimen name="drawer_header_text_size">20sp</dimen>
+ <item name="drawer_header_text_shadow_radius" format="float" type="dimen">4</item>
+ <item name="drawer_header_text_shadow_dy" format="float" type="dimen">2</item>
<!-- Folder open animation -->
<integer name="folder_translate_y_dist">300</integer>
diff --git a/res/values/preferences_defaults.xml b/res/values/preferences_defaults.xml
index 5693dbb75..fd82dbffa 100644
--- a/res/values/preferences_defaults.xml
+++ b/res/values/preferences_defaults.xml
@@ -6,6 +6,7 @@
<bool name="preferences_interface_homescreen_scrolling_page_outlines_default">@bool/config_workspaceDefaultShowOutlines</bool>
<bool name="preferences_interface_homescreen_scrolling_fade_adjacent_default">@@bool/config_workspaceFadeAdjacentScreens</bool>
<bool name="preferences_interface_homescreen_hide_icon_labels_default">false</bool>
+ <bool name="preferences_interface_homescreen_remote_folder_default">false</bool>
<string name="preferences_interface_drawer_scrolling_transition_effect">none</string>
<bool name="preferences_interface_drawer_scrolling_fade_adjacent_default">false</bool>
<bool name="preferences_interface_drawer_remove_hidden_apps_shortcuts_default">true</bool>
diff --git a/src/com/android/launcher3/AppDrawerListAdapter.java b/src/com/android/launcher3/AppDrawerListAdapter.java
index 3639e11f4..c68f52f7a 100644
--- a/src/com/android/launcher3/AppDrawerListAdapter.java
+++ b/src/com/android/launcher3/AppDrawerListAdapter.java
@@ -33,7 +33,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.SectionIndexer;
import com.android.launcher3.locale.LocaleSetManager;
@@ -53,6 +52,9 @@ import java.util.List;
public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdapter.ViewHolder>
implements View.OnLongClickListener, DragSource, SectionIndexer {
+ public static final String REMOTE_HEADER = "☆";
+ public static final String REMOTE_SCRUBBER = "★";
+
private static final String TAG = AppDrawerListAdapter.class.getSimpleName();
private static final String NUMERIC_OR_SPECIAL_HEADER = "#";
@@ -71,6 +73,34 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
}
}
+ private static class Bucket {
+ private int index;
+ private String startString;
+
+ public Bucket(int index, String startString) {
+ this.index = index;
+ this.startString = startString;
+ }
+ }
+
+ private static Bucket getBucketForApp(AppInfo app) {
+ if (app.hasFlag(AppInfo.REMOTE_APP_FLAG)) {
+ return new Bucket(Integer.MIN_VALUE, REMOTE_HEADER);
+ } else {
+ LocaleUtils localeUtils = LocaleUtils.getInstance();
+ int index = localeUtils.getBucketIndex(app.title.toString());
+ String start = localeUtils.getBucketLabel(index);
+ if (TextUtils.isEmpty(start)) {
+ start = NUMERIC_OR_SPECIAL_HEADER;
+ index = localeUtils.getBucketIndex(start);
+ }
+ return new Bucket(index, start);
+ }
+ }
+
+ private final RemoteFolderManager mRemoteFolderManager;
+
+ private HashSet<AppInfo> mAllApps;
private ArrayList<AppItemIndexedInfo> mHeaderList;
private LayoutInflater mLayoutInflater;
@@ -113,8 +143,11 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
}
public static class ViewHolder extends RecyclerView.ViewHolder {
- public AutoFitTextView mTextView;
- public ViewGroup mLayout;
+ public static int TYPE_NORMAL = 0;
+ public static int TYPE_CUSTOM = 1;
+
+ public AutoFitTextView mHeaderTextView;
+ public ViewGroup mIconLayout;
public View mContainerView;
public View mFadingBackgroundBackView;
public View mFadingBackgroundFrontView;
@@ -123,9 +156,9 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
mContainerView = itemView;
mFadingBackgroundBackView = itemView.findViewById(R.id.fading_background_back);
mFadingBackgroundFrontView = itemView.findViewById(R.id.fading_background_front);
- mTextView = (AutoFitTextView) itemView.findViewById(R.id.drawer_item_title);
- mTextView.bringToFront();
- mLayout = (ViewGroup) itemView.findViewById(R.id.drawer_item_flow);
+ mHeaderTextView = (AutoFitTextView) itemView.findViewById(R.id.drawer_item_title);
+ mHeaderTextView.bringToFront();
+ mIconLayout = (ViewGroup) itemView.findViewById(R.id.drawer_item_flow);
}
}
@@ -180,14 +213,14 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
public void add(ViewHolder holder) {
mViewHolderSet.add(holder);
- holder.mTextView.addOnLayoutChangeListener(mLayoutChangeListener);
+ holder.mHeaderTextView.addOnLayoutChangeListener(mLayoutChangeListener);
createAnimationHook(holder);
}
public void remove(ViewHolder holder) {
mViewHolderSet.remove(holder);
- holder.mTextView.removeOnLayoutChangeListener(mLayoutChangeListener);
+ holder.mHeaderTextView.removeOnLayoutChangeListener(mLayoutChangeListener);
}
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
@@ -252,8 +285,8 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
}
public void createAnimationHook(final ViewHolder holder) {
- holder.mTextView.animate().cancel();
- holder.mTextView.animate()
+ holder.mHeaderTextView.animate().cancel();
+ holder.mHeaderTextView.animate()
.setUpdateListener(new ItemAnimator(holder, mItemAnimatorSet))
.setListener(new AnimatorListenerAdapter() {
@Override
@@ -325,8 +358,8 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
// Scale header text letters
final float targetScale = (MAX_SCALE - MIN_SCALE) * percentage + MIN_SCALE;
- holder.mTextView.setScaleX(targetScale);
- holder.mTextView.setScaleY(targetScale);
+ holder.mHeaderTextView.setScaleX(targetScale);
+ holder.mHeaderTextView.setScaleY(targetScale);
// Perform animation
if (getSectionForPosition(holder.getPosition()) == mSectionTarget) {
@@ -370,8 +403,11 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
public AppDrawerListAdapter(Launcher launcher) {
mLauncher = launcher;
mHeaderList = new ArrayList<AppItemIndexedInfo>();
+ mAllApps = new HashSet<AppInfo>();
mLayoutInflater = LayoutInflater.from(launcher);
+ mRemoteFolderManager = mLauncher.getRemoteFolderManager();
+
mLocaleSetManager = new LocaleSetManager(mLauncher);
mLocaleSetManager.updateLocaleSet(mLocaleSetManager.getSystemLocaleSet());
mItemAnimatorSet = new ItemAnimatorSet(launcher);
@@ -388,7 +424,6 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
mItemAnimatorSet.onScrolled(recyclerView, dx, dy);
}
-
public void setDragging(boolean dragging) {
mItemAnimatorSet.setDragging(dragging);
}
@@ -400,6 +435,13 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
mItemAnimatorSet.setSectionTarget(sectionIndex);
}
+ /**
+ * @return the number of columns shown in the app drawer
+ */
+ public int getNumColumns() {
+ return mNumColumns;
+ }
+
private void initParams() {
mDeviceProfile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
@@ -407,7 +449,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
// set aside the space needed for the container character
int neededWidth = mLauncher.getResources()
- .getDimensionPixelSize(R.dimen.app_drawer_char_width);
+ .getDimensionPixelSize(R.dimen.drawer_header_text_char_width);
int availableWidth = mDeviceProfile.availableWidthPx - neededWidth;
mNumColumns = (int) Math.floor(availableWidth / iconWidth);
int leftOverPx = availableWidth % iconWidth;
@@ -432,79 +474,67 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
/**
* Create and populate mHeaderList (buckets for app sorting)
- * @param info
*/
- public void populateByCharacter(ArrayList<AppInfo> info) {
- if (info == null || info.size() <= 0) {
- Collections.sort(mHeaderList);
- return;
- }
+ public void populateByCharacter() {
+ mHeaderList.clear();
// Create a clone of AppInfo ArrayList to preserve data
- ArrayList<AppInfo> tempInfo = (ArrayList<AppInfo>) info.clone();
+ HashSet<AppInfo> appsToProcess = (HashSet<AppInfo>) mAllApps.clone();
+ while (!appsToProcess.isEmpty()) {
+ ArrayList<AppInfo> matchingApps = new ArrayList<AppInfo>();
- ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>();
+ AppInfo app = appsToProcess.iterator().next();
+ Bucket bucket = getBucketForApp(app);
- // get next app
- AppInfo app = tempInfo.get(0);
+ // Find other apps that fall into the same bucket
+ for (Iterator<AppInfo> iter = appsToProcess.iterator(); iter.hasNext(); ) {
+ AppInfo otherApp = iter.next();
+ Bucket otherBucket = getBucketForApp(otherApp);
- // get starting character
- LocaleUtils localeUtils = LocaleUtils.getInstance();
- int bucketIndex = localeUtils.getBucketIndex(app.title.toString());
- String startString
- = localeUtils.getBucketLabel(bucketIndex);
- if (TextUtils.isEmpty(startString)) {
- startString = NUMERIC_OR_SPECIAL_HEADER;
- bucketIndex = localeUtils.getBucketIndex(startString);
- }
-
- // now iterate through
- for (AppInfo info1 : tempInfo) {
- int newBucketIndex = localeUtils.getBucketIndex(info1.title.toString());
+ if (bucket.index == otherBucket.index) {
+ matchingApps.add(otherApp);
- String newChar
- = localeUtils.getBucketLabel(newBucketIndex);
- if (TextUtils.isEmpty(newChar)) {
- newChar = NUMERIC_OR_SPECIAL_HEADER;
- }
- // if same character
- if (newChar.equals(startString)) {
- // add it
- appInfos.add(info1);
+ // This app doesn't need to be processed again for other strings
+ iter.remove();
+ }
}
- }
-
- Collections.sort(appInfos, LauncherModel.getAppNameComparator());
- for (int i = 0; i < appInfos.size(); i += mNumColumns) {
- int endIndex = (int) Math.min(i + mNumColumns, appInfos.size());
- ArrayList<AppInfo> subList = new ArrayList<AppInfo>(appInfos.subList(i, endIndex));
- AppItemIndexedInfo indexInfo;
- indexInfo = new AppItemIndexedInfo(startString, bucketIndex, subList, i != 0);
- mHeaderList.add(indexInfo);
+ // Sort so they display in alphabetical order
+ Collections.sort(matchingApps, LauncherModel.getAppNameComparator());
+
+ // Split app list by number of columns and add rows to header list
+ for (int i = 0; i < matchingApps.size(); i += mNumColumns) {
+ int endIndex = Math.min(i + mNumColumns, matchingApps.size());
+ ArrayList<AppInfo> subList =
+ new ArrayList<AppInfo>(matchingApps.subList(i, endIndex));
+ AppItemIndexedInfo indexedInfo =
+ new AppItemIndexedInfo(bucket.startString, bucket.index, subList, i != 0);
+ mHeaderList.add(indexedInfo);
+ }
}
- for (AppInfo remove : appInfos) {
- // remove from mApps
- tempInfo.remove(remove);
- }
- populateByCharacter(tempInfo);
+ Collections.sort(mHeaderList);
}
- public void setApps(ArrayList<AppInfo> list) {
+ public void setApps(List<AppInfo> list) {
if (!LauncherAppState.isDisableAllApps()) {
initParams();
filterProtectedApps(list);
+ mAllApps.clear();
+ mAllApps.addAll(list);
- mHeaderList.clear();
- populateByCharacter(list);
- populateSectionHeaders();
- mLauncher.updateScrubber();
- this.notifyDataSetChanged();
+ processApps();
}
}
+ private void processApps() {
+ populateByCharacter();
+ populateSectionHeaders();
+ mLauncher.updateScrubber();
+ this.notifyDataSetChanged();
+ }
+
private void populateSectionHeaders() {
if (mSectionHeaders == null || mSectionHeaders.size() != mHeaderList.size()) {
mSectionHeaders = new LinkedHashMap<>();
@@ -521,128 +551,30 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
}
public void reset() {
- ArrayList<AppInfo> infos = getAllApps();
-
mLauncher.mAppDrawer.getLayoutManager().removeAllViews();
- setApps(infos);
- }
-
- private ArrayList<AppInfo> getAllApps() {
- ArrayList<AppInfo> indexedInfos = new ArrayList<AppInfo>();
-
- for (int j = 0; j < mHeaderList.size(); ++j) {
- AppItemIndexedInfo indexedInfo = mHeaderList.get(j);
- for (AppInfo info : indexedInfo.mInfo) {
- indexedInfos.add(info);
- }
- }
- return indexedInfos;
- }
-
- public void updateApps(ArrayList<AppInfo> list) {
- // We remove and re-add the updated applications list because it's properties may have
- // changed (ie. the title), and this will ensure that the items will be in their proper
- // place in the list.
- if (!LauncherAppState.isDisableAllApps()) {
- removeAppsWithoutInvalidate(list);
- addAppsWithoutInvalidate(list);
- reset();
- }
+ processApps();
}
-
- public void addApps(ArrayList<AppInfo> list) {
+ public void updateApps(List<AppInfo> list) {
if (!LauncherAppState.isDisableAllApps()) {
- addAppsWithoutInvalidate(list);
+ mAllApps.removeAll(list);
+ mAllApps.addAll(list);
reset();
}
}
- private void addAppsWithoutInvalidate(ArrayList<AppInfo> list) {
- // We add it in place, in alphabetical order
- LocaleUtils localeUtils = LocaleUtils.getInstance();
-
- int count = list.size();
- for (int i = 0; i < count; ++i) {
- AppInfo info = list.get(i);
- boolean found = false;
- AppItemIndexedInfo lastInfoForSection = null;
- int bucketIndex = localeUtils.getBucketIndex(info.title.toString());
- String start = localeUtils.getBucketLabel(bucketIndex);
- if (TextUtils.isEmpty(start)) {
- start = NUMERIC_OR_SPECIAL_HEADER;
- bucketIndex = localeUtils.getBucketIndex(start);
- }
- for (int j = 0; j < mHeaderList.size(); ++j) {
- AppItemIndexedInfo indexedInfo = mHeaderList.get(j);
- if (start.equals(indexedInfo.mStartString)) {
- Collections.sort(indexedInfo.mInfo, LauncherModel.getAppNameComparator());
- int index =
- Collections.binarySearch(indexedInfo.mInfo,
- info, LauncherModel.getAppNameComparator());
- if (index >= 0) {
- found = true;
- break;
- } else {
- lastInfoForSection = indexedInfo;
- }
- }
- }
- if (!found) {
- if (lastInfoForSection != null) {
- lastInfoForSection.mInfo.add(info);
- } else {
- // we need to create a new section
- ArrayList<AppInfo> newInfos = new ArrayList<AppInfo>();
- newInfos.add(info);
- AppItemIndexedInfo newInfo =
- new AppItemIndexedInfo(start, bucketIndex, newInfos, false);
- mHeaderList.add(newInfo);
- Collections.sort(mHeaderList);
- }
- }
- }
+ public void addApps(List<AppInfo> list) {
+ updateApps(list);
}
- public void removeApps(ArrayList<AppInfo> appInfos) {
+ public void removeApps(List<AppInfo> appInfos) {
if (!LauncherAppState.isDisableAllApps()) {
- removeAppsWithoutInvalidate(appInfos);
- //recreate everything
+ mAllApps.removeAll(appInfos);
reset();
}
}
- private void removeAppsWithoutInvalidate(ArrayList<AppInfo> list) {
- // loop through all the apps and remove apps that have the same component
- int length = list.size();
- for (int i = 0; i < length; ++i) {
- AppInfo info = list.get(i);
- for (int j = 0; j < mHeaderList.size(); ++j) {
- AppItemIndexedInfo indexedInfo = mHeaderList.get(j);
- ArrayList<AppInfo> clonedIndexedInfoApps =
- (ArrayList<AppInfo>) indexedInfo.mInfo.clone();
- int index =
- findAppByComponent(clonedIndexedInfoApps, info);
- if (index > -1) {
- indexedInfo.mInfo.remove(info);
- }
- }
- }
- }
-
- private int findAppByComponent(List<AppInfo> list, AppInfo item) {
- ComponentName removeComponent = item.intent.getComponent();
- int length = list.size();
- for (int i = 0; i < length; ++i) {
- AppInfo info = list.get(i);
- if (info.intent.getComponent().equals(removeComponent)) {
- return i;
- }
- }
- return -1;
- }
-
/*
* AllAppsView implementation
*/
@@ -655,28 +587,34 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
View v = LayoutInflater.from(parent.getContext()).
inflate(R.layout.app_drawer_item, parent, false);
ViewHolder holder = new ViewHolder(v);
- ViewGroup.LayoutParams params = holder.mTextView.getLayoutParams();
-
- // set the margin parameter to account for the text size of the icons so that the text view
- // is based on the icon size only
- if (params instanceof ViewGroup.MarginLayoutParams) {
- ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) params;
- marginParams.setMargins(marginParams.leftMargin, marginParams.topMargin,
- marginParams.rightMargin, marginParams.bottomMargin);
- holder.mTextView.setLayoutParams(marginParams);
- }
for (int i = 0; i < mNumColumns; i++) {
AppDrawerIconView icon = (AppDrawerIconView) mLayoutInflater.inflate(
- R.layout.drawer_icon, holder.mLayout, false);
+ R.layout.drawer_icon, holder.mIconLayout, false);
icon.setOnClickListener(mLauncher);
icon.setOnLongClickListener(this);
- holder.mLayout.addView(icon);
+ holder.mIconLayout.addView(icon);
+
+ icon.mIcon.setPadding(mDeviceProfile.iconDrawablePaddingPx,
+ mDeviceProfile.iconDrawablePaddingPx,
+ mDeviceProfile.iconDrawablePaddingPx,
+ mDeviceProfile.iconDrawablePaddingPx);
+ }
+
+ if (viewType == ViewHolder.TYPE_CUSTOM) {
+ mRemoteFolderManager.onCreateViewHolder(holder);
}
+
return holder;
}
@Override
+ public int getItemViewType(int position) {
+ return mHeaderList.get(position).isRemote() ?
+ ViewHolder.TYPE_CUSTOM : ViewHolder.TYPE_NORMAL;
+ }
+
+ @Override
public void onViewAttachedToWindow(ViewHolder holder) {
super.onViewAttachedToWindow(holder);
@@ -704,23 +642,24 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
AppItemIndexedInfo indexedInfo = mHeaderList.get(position);
- holder.mTextView.setVisibility(indexedInfo.isChild ? View.INVISIBLE : View.VISIBLE);
+
+ if (indexedInfo.isRemote()) {
+ mRemoteFolderManager.onBindViewHolder(holder, indexedInfo);
+ }
+
+ holder.mHeaderTextView.setVisibility(indexedInfo.isChild ? View.INVISIBLE : View.VISIBLE);
if (!indexedInfo.isChild) {
- if (indexedInfo.mStartString.equals(NUMERIC_OR_SPECIAL_HEADER)) {
- holder.mTextView.setText(NUMERIC_OR_SPECIAL_HEADER);
- } else {
- holder.mTextView.setText(String.valueOf(indexedInfo.mStartString));
- }
+ holder.mHeaderTextView.setText(indexedInfo.mStartString);
}
- holder.mTextView.setPivotX(0);
- holder.mTextView.setPivotY(holder.mTextView.getHeight() / 2);
+ holder.mHeaderTextView.setPivotX(0);
+ holder.mHeaderTextView.setPivotY(holder.mHeaderTextView.getHeight() / 2);
final int size = indexedInfo.mInfo.size();
- int childSize = holder.mLayout.getChildCount();
+ int childSize = holder.mIconLayout.getChildCount();
for (int i = 0; i < childSize; i++) {
- AppDrawerIconView icon = (AppDrawerIconView) holder.mLayout.getChildAt(i);
+ AppDrawerIconView icon = (AppDrawerIconView) holder.mIconLayout.getChildAt(i);
icon.setLayoutParams(mIconParams);
int extraStart = mExtraPadding;
int extraEnd = mExtraPadding;
@@ -742,13 +681,16 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
icon.setVisibility(View.VISIBLE);
AppInfo info = indexedInfo.mInfo.get(i);
icon.setTag(info);
- Drawable d = Utilities.createIconDrawable(info.iconBitmap);
+
+ Drawable d;
+ if (info.customDrawable != null) {
+ d = info.customDrawable;
+ } else {
+ d = Utilities.createIconDrawable(info.iconBitmap);
+ }
d.setBounds(mIconRect);
icon.mIcon.setImageDrawable(d);
- icon.mIcon.setPadding(mDeviceProfile.iconDrawablePaddingPx,
- mDeviceProfile.iconDrawablePaddingPx,
- mDeviceProfile.iconDrawablePaddingPx,
- mDeviceProfile.iconDrawablePaddingPx);
+
icon.mLabel.setText(info.title);
icon.mLabel.setVisibility(mHideIconLabels ? View.INVISIBLE : View.VISIBLE);
}
@@ -877,6 +819,14 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
}
return 0;
}
+
+ public boolean isRemote() {
+ return mStartString == REMOTE_HEADER;
+ }
+
+ public ArrayList<AppInfo> getInfo() {
+ return mInfo;
+ }
}
@Override
@@ -916,7 +866,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
return index;
}
- private void filterProtectedApps(ArrayList<AppInfo> list) {
+ private void filterProtectedApps(List<AppInfo> list) {
updateProtectedAppsList(mLauncher);
Iterator<AppInfo> iterator = list.iterator();
diff --git a/src/com/android/launcher3/AppDrawerScrubberSections.java b/src/com/android/launcher3/AppDrawerScrubberSections.java
index 2d4fcaaaa..6ac12fdbf 100644
--- a/src/com/android/launcher3/AppDrawerScrubberSections.java
+++ b/src/com/android/launcher3/AppDrawerScrubberSections.java
@@ -29,12 +29,23 @@ public class AppDrawerScrubberSections {
private static final int MAX_HEADERS = ALPHA_LETTERS.length() + MAX_NUMBER_CUSTOM_HEADERS;
public static final int INVALID_INDEX = -1;
+ /** Header strings which have different strings in the scrubber **/
+ private static final HashMap<String, String> sHeaderScrubberStringMap;
+ static {
+ sHeaderScrubberStringMap = new HashMap<String, String>();
+ sHeaderScrubberStringMap.put(AppDrawerListAdapter.REMOTE_HEADER,
+ AppDrawerListAdapter.REMOTE_SCRUBBER);
+ }
+
private AutoExpandTextView.HighlightedText mHighlightedText;
private int mPreviousValidIndex;
private int mNextValidIndex;
private int mAdapterIndex;
public AppDrawerScrubberSections(String text, boolean highlight, int idx) {
+ if (sHeaderScrubberStringMap.get(text) != null) {
+ text = sHeaderScrubberStringMap.get(text);
+ }
mHighlightedText = new AutoExpandTextView.HighlightedText(text, highlight);
mAdapterIndex = idx;
mPreviousValidIndex = mNextValidIndex = idx;
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 6d1350a59..d14b0e086 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -62,6 +62,7 @@ public class AppInfo extends ItemInfo {
static final int DOWNLOADED_FLAG = 1;
static final int UPDATED_SYSTEM_APP_FLAG = 2;
+ static final int REMOTE_APP_FLAG = 4;
int flags = 0;
@@ -92,6 +93,15 @@ public class AppInfo extends ItemInfo {
this.user = user;
}
+ public AppInfo(Intent intent, String title, UserHandleCompat user) {
+ this.componentName = intent.getComponent();
+ this.container = ItemInfo.NO_ID;
+
+ this.intent = intent;
+ this.title = title;
+ this.user = user;
+ }
+
public static int initFlags(LauncherActivityInfoCompat info) {
int appFlags = info.getApplicationInfo().flags;
int flags = 0;
@@ -128,6 +138,23 @@ public class AppInfo extends ItemInfo {
iconBitmap = info.iconBitmap;
}
+ /**
+ * Check if this app has a specific flag.
+ * @param flag flag to check.
+ * @return true if the flag is present, false otherwise.
+ */
+ public boolean hasFlag(int flag) {
+ return (flags & flag) != 0;
+ }
+
+ /**
+ * Set a flag for this app
+ * @param flag flag to apply.
+ */
+ public void setFlag(int flag) {
+ flags |= flag;
+ }
+
@Override
public String toString() {
return "ApplicationInfo(title=" + title.toString() + " id=" + this.id
@@ -159,4 +186,18 @@ public class AppInfo extends ItemInfo {
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
.putExtra(EXTRA_PROFILE, serialNumber);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (o != null && o instanceof AppInfo) {
+ return componentName.equals(((AppInfo) o).componentName);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return componentName.hashCode();
+ }
}
diff --git a/src/com/android/launcher3/AutoFitTextView.java b/src/com/android/launcher3/AutoFitTextView.java
index 208dd4073..3d6b65894 100644
--- a/src/com/android/launcher3/AutoFitTextView.java
+++ b/src/com/android/launcher3/AutoFitTextView.java
@@ -143,6 +143,14 @@ public class AutoFitTextView extends TextView {
setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()));
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setTextSize(float size) {
+ setRawTextSize(size);
+ }
+
private void setRawTextSize(float size) {
if (size != mMaxTextSize) {
mMaxTextSize = size;
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index d26577ac0..9bfde23a7 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -118,15 +118,21 @@ public class BubbleTextView extends TextView {
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
boolean setDefaultPadding, boolean promiseStateChanged) {
- Bitmap b = info.getIcon(iconCache);
LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
- iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
+ Drawable iconDrawable;
+ if (info.customDrawable != null) {
+ iconDrawable = info.customDrawable;
+ } else {
+ Bitmap b = info.getIcon(iconCache);
+ iconDrawable = Utilities.createIconDrawable(b);
+ ((FastBitmapDrawable) iconDrawable).setGhostModeEnabled(info.isDisabled != 0);
+ }
+ iconDrawable.setBounds(0, 0, grid.iconSizePx, grid.iconSizePx);
setCompoundDrawables(null, iconDrawable, null, null);
if (setDefaultPadding) {
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
}
if (info.contentDescription != null) {
@@ -144,7 +150,12 @@ public class BubbleTextView extends TextView {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- Drawable topDrawable = Utilities.createIconDrawable(info.iconBitmap);
+ Drawable topDrawable;
+ if (info.customDrawable != null) {
+ topDrawable = info.customDrawable;
+ } else {
+ topDrawable = Utilities.createIconDrawable(info.iconBitmap);
+ }
topDrawable.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx);
setCompoundDrawables(null, topDrawable, null, null);
setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
@@ -155,7 +166,6 @@ public class BubbleTextView extends TextView {
setTag(info);
}
-
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) {
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index ea058ea71..74b21df50 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -330,10 +330,16 @@ public class DeleteDropTarget extends ButtonDropTarget {
} else if (isWorkspaceOrFolderApplication(d)) {
LauncherModel.deleteItemFromDatabase(mLauncher, item);
} else if (isWorkspaceFolder(d)) {
- // Remove the folder from the workspace and delete the contents from launcher model
FolderInfo folderInfo = (FolderInfo) item;
- mLauncher.removeFolder(folderInfo);
- LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo);
+
+ // Remote folder should not really be deleted. Let the manager handle it.
+ if (folderInfo.isRemote()) {
+ mLauncher.getRemoteFolderManager().onFolderDeleted();
+ } else {
+ // Remove the folder from the workspace and delete the contents from launcher model
+ mLauncher.removeFolder(folderInfo);
+ LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo);
+ }
} else if (isWorkspaceOrFolderWidget(d)) {
// Remove the widget from the workspace
mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index d10be4efc..486d5e514 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -37,7 +37,6 @@ import android.support.v4.widget.AutoScrollHelper;
import android.text.InputType;
import android.text.Selection;
import android.text.Spannable;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -49,6 +48,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateInterpolator;
@@ -102,7 +102,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
private int mMaterialExpandDuration;
private int mMaterialExpandStagger;
protected CellLayout mContent;
- private ScrollView mScrollView;
+ protected ScrollView mScrollView;
private final LayoutInflater mInflater;
private final IconCache mIconCache;
private int mState = STATE_NONE;
@@ -132,7 +132,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
private boolean mDeleteFolderOnDropCompleted = false;
private boolean mSuppressFolderDeletion = false;
private boolean mItemAddedBackToSelfViaIcon = false;
- View mFolderNameLockContainer;
+ protected View mFolderNameLockContainer;
FolderEditText mFolderName;
ImageView mFolderLock;
private int mScreenWidth;
@@ -218,7 +218,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
super.onFinishInflate();
mScrollView = (ScrollView) findViewById(R.id.scroll_view);
mContent = (CellLayout) findViewById(R.id.folder_content);
- int measureSpec = MeasureSpec.UNSPECIFIED;
mFocusIndicatorHandler = new FocusIndicatorView(getContext());
mContent.addView(mFocusIndicatorHandler, 0);
@@ -232,16 +231,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mContent.setGridSize(0, 0);
mContent.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
mContent.setInvertIfRtl(true);
- mFolderNameLockContainer = findViewById(R.id.folder_name_lock_container);
+
mFolderName = (FolderEditText) findViewById(R.id.folder_name);
mFolderName.setFolder(this);
mFolderName.setOnFocusChangeListener(this);
- // We find out how tall the text view wants to be (it is set to wrap_content), so that
- // we can allocate the appropriate amount of space for it.
- mFolderName.measure(measureSpec, measureSpec);
- mFolderNameHeight = mFolderName.getMeasuredHeight();
-
// We disable action mode for now since it messes up the view on phones
mFolderName.setCustomSelectionActionModeCallback(mActionModeCallback);
mFolderName.setOnEditorActionListener(this);
@@ -257,11 +251,13 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mFolderName.setVisibility(View.GONE);
}
+ mFolderNameLockContainer = findViewById(R.id.folder_name_lock_container);
mFolderLock = (ImageView) findViewById(R.id.folder_lock);
- mFolderLock.measure(measureSpec, measureSpec);
- mFolderLock.setOnClickListener(this);
- mFolderLockHeight = mFolderLock.getMeasuredHeight();
+ // Could be null if this Folder an instance of the RemoteFolder subclass
+ if (mFolderLock != null) {
+ mFolderLock.setOnClickListener(this);
+ }
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
mScreenWidth = displayMetrics.widthPixels;
}
@@ -476,7 +472,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
}
- void bind(FolderInfo info) {
+ void bind(final FolderInfo info) {
mInfo = info;
ArrayList<ShortcutInfo> children = info.contents;
ArrayList<ShortcutInfo> overflow = new ArrayList<ShortcutInfo>();
@@ -533,11 +529,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
* Creates a new UserFolder, inflated from R.layout.user_folder.
*
* @param context The application's context.
+ * @param root The {@link View} parent of this folder.
*
* @return A new UserFolder.
*/
- static Folder fromXml(Context context) {
- return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
+ static Folder fromXml(Context context, ViewGroup root) {
+ return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, root, false);
}
/**
@@ -659,7 +656,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
circX, circY, 0, mScreenWidth);
final View[] alphaViewSet = new View[] { mFolderNameLockContainer,
- mContent, mFolderName, mFolderLock };
+ mContent, mFolderName, mFolderLock };
+
for (View view : alphaViewSet) {
view.setAlpha(0f);
}
@@ -1218,7 +1216,16 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
// Do nothing
}
+ /**
+ * @return true if contents should persist their status to the database.
+ */
+ protected boolean shouldUpdateContentsInDatabase() {
+ return true;
+ }
+
private void updateItemLocationsInDatabase() {
+ if (!shouldUpdateContentsInDatabase()) return;
+
ArrayList<View> list = getItemsInReadingOrder();
for (int i = 0; i < list.size(); i++) {
View v = list.get(i);
@@ -1229,6 +1236,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
private void updateItemLocationsInDatabaseBatch() {
+ if (!shouldUpdateContentsInDatabase()) return;
+
ArrayList<View> list = getItemsInReadingOrder();
ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
for (int i = 0; i < list.size(); i++) {
@@ -1241,6 +1250,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
public void addItemLocationsInDatabase() {
+ if (!shouldUpdateContentsInDatabase()) return;
+
ArrayList<View> list = getItemsInReadingOrder();
for (int i = 0; i < list.size(); i++) {
View v = list.get(i);
@@ -1260,7 +1271,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
return true;
}
- private void setupContentDimensions(int count) {
+ protected void setupContentDimensions(int count) {
ArrayList<View> list = getItemsInReadingOrder();
int countX = mContent.getCountX();
@@ -1297,12 +1308,19 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
return mMaxNumItems;
}
- private void centerAboutIcon() {
+ protected void centerAboutIcon() {
+ requestLayout();
+ int width = getMeasuredWidth();
+ int height = getMeasuredHeight();
+ if (width > 0 && height > 0) {
+ centerAboutIcon(width, height);
+ }
+ }
+
+ private void centerAboutIcon(int width, int height) {
DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
DragLayer parent = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
- int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
- int height = getFolderHeight();
float scale = parent.getDescendantRectRelativeToSelf(mFolderIcon, mTempRect);
@@ -1329,6 +1347,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
int left = (grid.availableWidthPx - width) / 2;
// Drop the top down a little so it isn't bounded by the page indicators
int top = (int) (bounds.top + (bounds.height() * 1.15) - height);
+ // Make sure the top margin stays consistent
+ lp.topMargin = getResources().getDimensionPixelSize(R.dimen.folder_margin);
if (width >= bounds.width()) {
// If the folder doesn't fit within the bounds, center it about the desired bounds
@@ -1361,38 +1381,17 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
private void setupContentForNumItems(int count) {
setupContentDimensions(count);
-
- DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
- if (lp == null) {
- lp = new DragLayer.LayoutParams(0, 0);
- lp.customPosition = true;
- setLayoutParams(lp);
- }
- centerAboutIcon();
}
- private int getContentAreaHeight() {
+ protected int getContentAreaHeight() {
return Math.max(mContent.getDesiredHeight(), MIN_CONTENT_DIMEN);
}
- private int getContentAreaWidth() {
+ protected int getContentAreaWidth() {
return Math.max(mContent.getDesiredWidth(), MIN_CONTENT_DIMEN);
}
- private int getFolderHeight() {
- int height = getPaddingTop() + getPaddingBottom() + mFolderNameHeight
- + getContentAreaHeight();
- return height;
- }
-
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
- int height = getFolderHeight();
- int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(),
- MeasureSpec.EXACTLY);
- int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(getContentAreaHeight(),
- MeasureSpec.EXACTLY);
-
if (LauncherAppState.isDisableAllApps()) {
// Don't cap the height of the content to allow scrolling.
mContent.setFixedSize(getContentAreaWidth(), mContent.getDesiredHeight());
@@ -1400,14 +1399,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mContent.setFixedSize(getContentAreaWidth(), getContentAreaHeight());
}
- mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec);
- if (TextUtils.isEmpty(mInfo.title)) {
- mFolderName.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec(
- mFolderNameHeight, MeasureSpec.EXACTLY));
- }
- mFolderNameLockContainer.measure(contentAreaWidthSpec,
- MeasureSpec.makeMeasureSpec(mFolderNameHeight,MeasureSpec.EXACTLY));
- setMeasuredDimension(width, height);
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void arrangeChildren(ArrayList<View> list) {
@@ -1427,8 +1419,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
if (info.cellX != vacant[0] || info.cellY != vacant[1]) {
info.cellX = vacant[0];
info.cellY = vacant[1];
- LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0,
- info.cellX, info.cellY);
+
+ if (shouldUpdateContentsInDatabase()) {
+ LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0,
+ info.cellX, info.cellY);
+ }
}
boolean insert = false;
mContent.addViewToCellLayout(v, insert ? 0 : -1, (int)info.id, lp, true);
@@ -1467,7 +1462,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mSuppressFolderDeletion = false;
}
- private void replaceFolderWithFinalItem() {
+ protected void replaceFolderWithFinalItem() {
if (mInfo.hidden && getItemCount() >= 1) {
return;
}
@@ -1557,8 +1552,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
// Actually move the item in the database if it was an external drag. Call this
// before creating the view, so that ShortcutInfo is updated appropriately.
- LauncherModel.addOrMoveItemInDatabase(
- mLauncher, si, mInfo.id, 0, si.cellX, si.cellY);
+ if (shouldUpdateContentsInDatabase()) {
+ LauncherModel.addOrMoveItemInDatabase(
+ mLauncher, si, mInfo.id, 0, si.cellX, si.cellY);
+ }
// We only need to update the locations if it doesn't get handled in #onDropCompleted.
if (d.dragSource != this) {
@@ -1624,8 +1621,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
findAndSetEmptyCells(item);
}
createAndAddShortcut(item);
- LauncherModel.addOrMoveItemInDatabase(
- mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+
+ if (shouldUpdateContentsInDatabase()) {
+ LauncherModel.addOrMoveItemInDatabase(
+ mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+ }
}
public void onRemove(ShortcutInfo item) {
@@ -1633,8 +1633,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
// If this item is being dragged from this open folder, we have already handled
// the work associated with removing the item, so we don't have to do anything here.
if (item == mCurrentDragInfo) return;
- View v = getViewForInfo(item);
- mContent.removeView(v);
+ mContent.removeView(getViewForInfo(item));
if (mState == STATE_ANIMATING) {
mRearrangeOnClose = true;
} else {
@@ -1645,16 +1644,52 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
}
}
- private View getViewForInfo(ShortcutInfo item) {
- for (int j = 0; j < mContent.getCountY(); j++) {
- for (int i = 0; i < mContent.getCountX(); i++) {
- View v = mContent.getChildAt(i, j);
- if (v.getTag() == item) {
- return v;
- }
+ @Override
+ public void onRemoveAll() {
+ // Clear the UX after folder contents are removed from the DB
+ removeViewsForItems(null);
+ mLauncher.closeFolder(this);
+ replaceFolderWithFinalItem();
+ }
+
+ @Override
+ public void onRemoveAll(ArrayList<ShortcutInfo> items) {
+ removeViewsForItems(items);
+ if (mInfo.contents.isEmpty()) {
+ mLauncher.closeFolder(this);
+ }
+ replaceFolderWithFinalItem();
+ }
+
+ /**
+ * Remove all the supplied item views from this folder.
+ * @param items info of views to remove, or null if all views should be removed.
+ */
+ protected void removeViewsForItems(ArrayList<ShortcutInfo> items) {
+ if (items == null) {
+ mContent.removeAllViews();
+ } else {
+ for (ShortcutInfo item : items) {
+ mContent.removeView(getViewForInfo(item));
}
}
- return null;
+ }
+
+ /**
+ * Update the view tied to this shortcut.
+ * @param info updated info to be applied to view.
+ */
+ public void updateViewForInfo(final ShortcutInfo info) {
+ View v = getViewForInfo(info);
+ if (v != null & v instanceof BubbleTextView) {
+ ((BubbleTextView) v).applyFromShortcutInfo(info, mIconCache, false);
+
+ mItemsInvalidated = true;
+ }
+ }
+
+ public View getViewForInfo(ShortcutInfo item) {
+ return mContent.getChildAt(item.cellX, item.cellY);
}
public void onItemsChanged() {
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index 214ec3241..c9f7556c1 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -170,7 +170,16 @@ public class FolderIcon extends FrameLayout implements FolderListener {
icon.mLauncher = launcher;
icon.setContentDescription(String.format(launcher.getString(R.string.folder_name_format),
folderInfo.title));
- Folder folder = Folder.fromXml(launcher);
+ Folder folder;
+ if (folderInfo.isRemote()) {
+ folder = launcher.getRemoteFolderManager().createRemoteFolder(icon, launcher.getDragLayer());
+ if (folder == null) {
+ LauncherModel.deleteItemFromDatabase(launcher, folderInfo);
+ return null;
+ }
+ } else {
+ folder = Folder.fromXml(launcher, launcher.getDragLayer());
+ }
folder.setDragController(launcher.getDragController());
folder.setFolderIcon(icon);
folder.bind(folderInfo);
@@ -232,6 +241,11 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
}
+ // Create an overlay badge if this FolderIcon is for a RemoteFolder
+ if (folderInfo.isRemote()) {
+ icon = RemoteFolderManager.addBadgeToFolderIcon(icon);
+ }
+
return icon;
}
@@ -366,10 +380,14 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
private boolean willAcceptItem(ItemInfo item) {
+ if (mInfo.isRemote()) return false;
+
final int itemType = item.itemType;
boolean hidden = false;
if (item instanceof FolderInfo){
+ if (((FolderInfo) item).isRemote()) return false;
+
hidden = ((FolderInfo) item).hidden;
}
return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
@@ -683,7 +701,7 @@ public class FolderIcon extends FrameLayout implements FolderListener {
super.dispatchDraw(canvas);
if (mFolder == null) return;
- if (mFolder.getItemCount() == 0 && !mAnimating) return;
+ if (mFolder.getItemCount() == 0 && !mAnimating && !mInfo.isRemote()) return;
ArrayList<View> items = mFolder.getItemsInReadingOrder();
Drawable d;
@@ -692,13 +710,13 @@ public class FolderIcon extends FrameLayout implements FolderListener {
// Update our drawing parameters if necessary
if (mAnimating) {
computePreviewDrawingParams(mAnimParams.drawable);
- } else {
+ } else if (!items.isEmpty()) {
v = (TextView) items.get(0);
d = getTopDrawable(v);
- computePreviewDrawingParams(d);
+ if (d != null) computePreviewDrawingParams(d);
}
- int nItemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
+ int ntemsInPreview = Math.min(items.size(), NUM_ITEMS_IN_PREVIEW);
// Hidden folder - don't display Preview
View folderLock = findViewById(R.id.folder_lock_image);
@@ -717,17 +735,22 @@ public class FolderIcon extends FrameLayout implements FolderListener {
}
if (!mAnimating) {
- for (int i = NUM_ITEMS_IN_PREVIEW; i >= 0; i--) {
+ for (int i = 0; i < NUM_ITEMS_IN_PREVIEW; i++) {
d = null;
- if (i < items.size()) {
+ if (mInfo.isRemote()) {
+ d = mLauncher.getRemoteFolderManager().getFolderIconDrawable(items, i);
+ } else if (i < items.size()) {
v = (TextView) items.get(i);
if (!mHiddenItems.contains(v.getTag())) {
d = getTopDrawable(v);
- mParams = computePreviewItemDrawingParams(i, mParams);
- mParams.drawable = d;
}
}
+ if (d != null) {
+ mParams = computePreviewItemDrawingParams(i, mParams);
+ mParams.drawable = d;
+ }
+
ImageView appIcon = null;
switch(i) {
case 0:
@@ -826,6 +849,18 @@ public class FolderIcon extends FrameLayout implements FolderListener {
requestLayout();
}
+ @Override
+ public void onRemoveAll() {
+ invalidate();
+ requestLayout();
+ }
+
+ @Override
+ public void onRemoveAll(ArrayList<ShortcutInfo> items) {
+ invalidate();
+ requestLayout();
+ }
+
public void onTitleChanged(CharSequence title) {
mFolderName.setText(title.toString());
setContentDescription(String.format(getContext().getString(R.string.folder_name_format),
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 104bd6cc1..bed1a5d47 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -28,11 +28,13 @@ import java.util.Arrays;
* Represents a folder containing shortcuts or apps.
*/
public class FolderInfo extends ItemInfo {
+ public static final int REMOTE_SUBTYPE = 1;
/**
* Whether this folder has been opened
*/
boolean opened;
+ int subType;
/**
* The apps and shortcuts and hidden status
@@ -73,6 +75,50 @@ public class FolderInfo extends ItemInfo {
itemsChanged();
}
+ /**
+ * Remove all apps and shortcuts. Does not change the DB unless
+ * LauncherModel.deleteFolderContentsFromDatabase(Context, FolderInfo) is called first.
+ */
+ public void removeAll() {
+ contents.clear();
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).onRemoveAll();
+ }
+ itemsChanged();
+ }
+
+ /**
+ * Remove all supplied shortcuts. Does not change the DB unless
+ * LauncherModel.deleteFolderContentsFromDatabase(Context, FolderInfo) is called first.
+ * @param items the shortcuts to remove.
+ */
+ public void removeAll(ArrayList<ShortcutInfo> items) {
+ contents.removeAll(items);
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).onRemoveAll(items);
+ }
+ itemsChanged();
+ }
+
+ /**
+ * @return true if this info represents a remote folder, false otherwise
+ */
+ public boolean isRemote() {
+ return (subType & REMOTE_SUBTYPE) != 0;
+ }
+
+ /**
+ * Set flag indicating whether this folder is remote
+ * @param remote true if folder is remote, false otherwise
+ */
+ public void setRemote(final boolean remote) {
+ if (remote) {
+ subType |= REMOTE_SUBTYPE;
+ } else {
+ subType &= ~REMOTE_SUBTYPE;
+ }
+ }
+
public void setTitle(CharSequence title) {
this.title = title;
for (int i = 0; i < listeners.size(); i++) {
@@ -85,6 +131,7 @@ public class FolderInfo extends ItemInfo {
super.onAddToDatabase(context, values);
values.put(LauncherSettings.Favorites.TITLE, title.toString());
values.put(LauncherSettings.Favorites.HIDDEN, hidden ? 1 : 0);
+ values.put(LauncherSettings.BaseLauncherColumns.SUBTYPE, subType);
}
void addListener(FolderListener listener) {
@@ -110,15 +157,17 @@ public class FolderInfo extends ItemInfo {
}
interface FolderListener {
- public void onAdd(ShortcutInfo item);
- public void onRemove(ShortcutInfo item);
- public void onTitleChanged(CharSequence title);
- public void onItemsChanged();
+ void onAdd(ShortcutInfo item);
+ void onRemove(ShortcutInfo item);
+ void onRemoveAll();
+ void onRemoveAll(ArrayList<ShortcutInfo> items);
+ void onTitleChanged(CharSequence title);
+ void onItemsChanged();
}
@Override
public String toString() {
- return "FolderInfo(id=" + this.id + " type=" + this.itemType
+ return "FolderInfo(id=" + this.id + " type=" + this.itemType + " subtype=" + this.subType
+ " container=" + this.container + " screen=" + screenId
+ " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
+ " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + ")";
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 91af5873e..5c1bc0d55 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -20,6 +20,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
import android.util.Log;
import com.android.launcher3.compat.UserHandleCompat;
@@ -125,6 +126,12 @@ public class ItemInfo {
UserHandleCompat user;
+ /**
+ * A custom drawable to use for the icon. Not persisted to the database because
+ * it is not guaranteed to be a bitmap (could be a vector).
+ */
+ Drawable customDrawable;
+
ItemInfo() {
user = UserHandleCompat.myUserHandle();
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 030e2712d..44f8f4fe1 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -32,9 +32,7 @@ import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
-import android.app.Dialog;
import android.app.SearchManager;
-import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
@@ -62,7 +60,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
@@ -73,8 +70,6 @@ import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
-import android.os.UserHandle;
-import android.preference.PreferenceManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Selection;
@@ -82,7 +77,6 @@ import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
-import android.util.Pair;
import android.view.Display;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -124,7 +118,6 @@ import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.PagedView.TransitionEffect;
import com.android.launcher3.settings.SettingsProvider;
import com.android.launcher3.stats.LauncherStats;
-import com.android.launcher3.stats.internal.service.AggregationIntentService;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -294,6 +287,7 @@ public class Launcher extends Activity
private DynamicGridSizeFragment mDynamicGridSizeFragment;
private LauncherClings mLauncherClings;
protected HiddenFolderFragment mHiddenFolderFragment;
+ private RemoteFolderManager mRemoteFolderManager;
private AppWidgetManagerCompat mAppWidgetManager;
private LauncherAppWidgetHost mAppWidgetHost;
@@ -512,6 +506,8 @@ public class Launcher extends Activity
mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
mAppWidgetHost.startListening();
+ mRemoteFolderManager = new RemoteFolderManager(this);
+
// If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
// this also ensures that any synchronous binding below doesn't re-trigger another
// LauncherModel load.
@@ -2252,6 +2248,14 @@ public class Launcher extends Activity
return mWorkspace;
}
+ public RemoteFolderManager getRemoteFolderManager() {
+ return mRemoteFolderManager;
+ }
+
+ public AppDrawerListAdapter getAppDrawerListAdapter() {
+ return mAppDrawerAdapter;
+ }
+
public Hotseat getHotseat() {
return mHotseat;
}
@@ -2814,10 +2818,14 @@ public class Launcher extends Activity
}
FolderIcon addFolder(CellLayout layout, long container, final long screenId, int cellX,
- int cellY) {
- final FolderInfo folderInfo = new FolderInfo();
+ int cellY) {
+ FolderInfo folderInfo = new FolderInfo();
folderInfo.title = getText(R.string.folder_name);
+ return addFolder(layout, container, screenId, cellX, cellY, folderInfo);
+ }
+ FolderIcon addFolder(CellLayout layout, long container, final long screenId, int cellX,
+ int cellY, FolderInfo folderInfo) {
// Update the model
LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screenId, cellX, cellY,
false);
@@ -2987,10 +2995,11 @@ public class Launcher extends Activity
} else if (v == mAllAppsButton) {
onClickAllAppsButton(v);
} else if (tag instanceof AppInfo) {
+ AppInfo info = (AppInfo) tag;
startAppShortcutOrInfoActivity(v);
LauncherApplication.getLauncherStats().sendAppLaunchEvent(
- LauncherStats.ORIGIN_APPDRAWER, ((AppInfo)tag).componentName.getPackageName());
- String packageName = ((AppInfo)tag).getIntent().getComponent().getPackageName();
+ LauncherStats.ORIGIN_APPDRAWER, info.componentName.getPackageName());
+ String packageName = info.getIntent().getComponent().getPackageName();
if (LauncherStats.SETTINGS_PACKAGE_NAME.equals(packageName)) {
LauncherApplication.getLauncherStats()
.sendSettingsOpenedEvent(LauncherStats.ORIGIN_APPDRAWER);
@@ -3845,6 +3854,7 @@ public class Launcher extends Activity
if (drawer && contentType == AppsCustomizePagedView.ContentType.Applications) {
toView = findViewById(R.id.app_drawer_container);
+ mRemoteFolderManager.onAppDrawerOpened();
} else {
toView = mAppsCustomizeTabHost;
}
@@ -4872,6 +4882,7 @@ public class Launcher extends Activity
addedApps != null && mAppsCustomizeContent != null) {
mAppsCustomizeContent.addApps(addedApps);
mAppDrawerAdapter.addApps(addedApps);
+ mRemoteFolderManager.onBindAddApps(addedApps);
}
}
@@ -4895,7 +4906,7 @@ public class Launcher extends Activity
final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
final Collection<Animator> bounceAnims = new ArrayList<Animator>();
final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
- Workspace workspace = mWorkspace;
+ final Workspace workspace = mWorkspace;
long newShortcutsScreenId = -1;
for (int i = start; i < end; i++) {
final ItemInfo item = shortcuts.get(i);
@@ -4946,12 +4957,14 @@ public class Launcher extends Activity
}
break;
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
+ final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
(ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
(FolderInfo) item, mIconCache);
- newFolder.setTextVisible(!mHideIconLabels);
- workspace.addInScreenFromBind(newFolder, item.container, item.screenId, item.cellX,
- item.cellY, 1, 1);
+ if (newFolder != null) {
+ newFolder.setTextVisible(!mHideIconLabels);
+ workspace.addInScreenFromBind(newFolder, item.container, item.screenId, item.cellX,
+ item.cellY, 1, 1);
+ }
break;
default:
throw new RuntimeException("Invalid Item Type");
@@ -5203,6 +5216,8 @@ public class Launcher extends Activity
mWorkspace.resetOverviewMode();
}
mModel.updateCount();
+
+ mRemoteFolderManager.bindFinished();
}
private void sendLoadingCompleteBroadcastIfNecessary() {
@@ -5289,6 +5304,7 @@ public class Launcher extends Activity
} else {
if (mAppDrawerAdapter != null) {
mAppDrawerAdapter.setApps(apps);
+ mRemoteFolderManager.onSetApps();
}
if (mAppsCustomizeContent != null) {
mAppsCustomizeContent.setApps(apps);
@@ -5433,7 +5449,7 @@ public class Launcher extends Activity
for (AppInfo info : appInfos) {
removedComponents.add(info.componentName);
}
- if (!packageNames.isEmpty()) {
+ if (packageNames != null && !packageNames.isEmpty()) {
mWorkspace.removeItemsByPackageName(packageNames, user);
}
if (!removedComponents.isEmpty()) {
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index eab9861bd..3facb3c21 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -66,7 +66,7 @@ public class LauncherApplication extends Application {
if (getResources().getBoolean(R.bool.config_launcher_stkAppRename)) {
registerAppNameChangeReceiver();
}
- sLauncherStats = LauncherStats.createInstance(this);
+ sLauncherStats = LauncherStats.getInstance(this);
AggregationIntentService.scheduleService(this);
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index dae2c180f..5470e177d 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -30,7 +30,6 @@ import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.content.pm.LauncherApps.Callback;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
@@ -933,10 +932,10 @@ public class LauncherModel extends BroadcastReceiver
String userSerial = Long.toString(UserManagerCompat.getInstance(context)
.getSerialNumberForUser(user));
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[] { "title", "intent", "profileId" },
- "title=? and (intent=? or intent=?) and profileId=?",
- new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },
- null);
+ new String[] { "title", "intent", "profileId" },
+ "title=? and (intent=? or intent=?) and profileId=?",
+ new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial},
+ null);
try {
return c.moveToFirst();
} finally {
@@ -1012,6 +1011,7 @@ public class LauncherModel extends BroadcastReceiver
final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
final int hiddenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.HIDDEN);
+ final int subType = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SUBTYPE);
FolderInfo folderInfo = null;
switch (c.getInt(itemTypeIndex)) {
@@ -1027,6 +1027,7 @@ public class LauncherModel extends BroadcastReceiver
folderInfo.cellX = c.getInt(cellXIndex);
folderInfo.cellY = c.getInt(cellYIndex);
folderInfo.hidden = c.getInt(hiddenIndex) > 0;
+ folderInfo.subType = subType;
return folderInfo;
}
@@ -2126,6 +2127,7 @@ public class LauncherModel extends BroadcastReceiver
//final int displayModeIndex = c.getColumnIndexOrThrow(
final int hiddenIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.HIDDEN);
+ final int subTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SUBTYPE);
//final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI); //final int displayModeIndex = c.getColumnIndexOrThrow(
// LauncherSettings.Favorites.DISPLAY_MODE);
@@ -2363,6 +2365,7 @@ public class LauncherModel extends BroadcastReceiver
folderInfo.spanX = 1;
folderInfo.spanY = 1;
folderInfo.hidden = c.getInt(hiddenIndex) > 0;
+ folderInfo.subType = c.getInt(subTypeIndex);
// check & update map of what's occupied
if (!checkItemPlacement(occupied, folderInfo, shouldResize)) {
@@ -2859,7 +2862,7 @@ public class LauncherModel extends BroadcastReceiver
}
workspaceItems.remove(i);
folders.remove(Long.valueOf(item.id));
- } else if (folder.contents.size() == 0 /*&& !(folder instanceof LiveFolderInfo)*/) {
+ } else if (folder.contents.size() == 0 && !folder.isRemote()) {
LauncherModel.deleteFolderContentsFromDatabase(mContext, folder);
workspaceItems.remove(i);
folders.remove(Long.valueOf(item.id));
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 14492488a..abe082eaa 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -67,7 +67,7 @@ public class LauncherProvider extends ContentProvider {
private static final String TAG = "Launcher.LauncherProvider";
private static final boolean LOGD = false;
- private static final int DATABASE_VERSION = 22;
+ private static final int DATABASE_VERSION = 23;
static final String OLD_AUTHORITY = "com.android.launcher2.settings";
static final String AUTHORITY = ProviderConfig.AUTHORITY;
@@ -505,7 +505,8 @@ public class LauncherProvider extends ContentProvider {
"modified INTEGER NOT NULL DEFAULT 0," +
"restored INTEGER NOT NULL DEFAULT 0," +
"profileId INTEGER DEFAULT " + userSerialNumber +
- ",hidden INTEGER DEFAULT 0" +
+ ",hidden INTEGER DEFAULT 0," +
+ "subType INTEGER DEFAULT 0" +
");");
addWorkspacesTable(db);
@@ -995,6 +996,21 @@ public class LauncherProvider extends ContentProvider {
version = 22;
}
+ if (version < 23) {
+ db.beginTransaction();
+ try {
+ db.execSQL("ALTER TABLE favorites " +
+ "ADD COLUMN subType INTEGER DEFAULT 0;");
+ db.setTransactionSuccessful();
+ version = 23;
+ } catch (SQLException ex) {
+ // Old version remains, which means we wipe old data
+ Log.e(TAG, ex.getMessage(), ex);
+ } finally {
+ db.endTransaction();
+ }
+ }
+
if (version != DATABASE_VERSION) {
Log.w(TAG, "Destroying all old data.");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 357bac52d..d7df5a714 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -45,6 +45,10 @@ class LauncherSettings {
static final String HIDDEN = "hidden";
/**
+ * Folder subtype, used for Remote Folders
+ */
+ static final String SUBTYPE = "subType";
+ /**
* The Intent URL of the gesture, describing what it points to. This
* value is given to {@link android.content.Intent#parseUri(String, int)} to create
* an Intent that can be launched.
diff --git a/src/com/android/launcher3/OverviewSettingsPanel.java b/src/com/android/launcher3/OverviewSettingsPanel.java
index fef164383..92f2bd46a 100644
--- a/src/com/android/launcher3/OverviewSettingsPanel.java
+++ b/src/com/android/launcher3/OverviewSettingsPanel.java
@@ -10,6 +10,10 @@ import android.widget.ImageView;
import android.widget.ListView;
import com.android.launcher3.list.PinnedHeaderListView;
import com.android.launcher3.list.SettingsPinnedHeaderAdapter;
+import com.android.launcher3.settings.SettingsProvider;
+
+import java.util.ArrayList;
+import java.util.Arrays;
public class OverviewSettingsPanel {
public static final String ANDROID_SETTINGS = "com.android.settings";
@@ -41,13 +45,6 @@ public class OverviewSettingsPanel {
res.getString(R.string.drawer_settings),
res.getString(R.string.app_settings)};
- String[] values = new String[]{
- res.getString(R.string.home_screen_search_text),
- res.getString(R.string.scroll_effect_text),
- res.getString(R.string.icon_labels),
- res.getString(R.string.scrolling_wallpaper),
- res.getString(R.string.grid_size_text)};
-
String[] valuesDrawer = new String[] {
res.getString(R.string.drawer_type),
res.getString(R.string.scroll_effect_text),
@@ -58,7 +55,6 @@ public class OverviewSettingsPanel {
res.getString(R.string.larger_icons_text),
res.getString(R.string.protected_app_settings)};
-
mSettingsAdapter = new SettingsPinnedHeaderAdapter(mLauncher);
mSettingsAdapter.setHeaders(headers);
mSettingsAdapter.addPartition(false, true);
@@ -66,7 +62,8 @@ public class OverviewSettingsPanel {
mSettingsAdapter.addPartition(false, true);
mSettingsAdapter.mPinnedHeaderCount = headers.length;
- mSettingsAdapter.changeCursor(HOME_SETTINGS_POSITION, createCursor(headers[0], values));
+ mSettingsAdapter.changeCursor(HOME_SETTINGS_POSITION,
+ createCursor(headers[0], getValues()));
mSettingsAdapter.changeCursor(DRAWER_SETTINGS_POSITION, createCursor(headers[1],
valuesDrawer));
mSettingsAdapter.changeCursor(APP_SETTINGS_POSITION, createCursor(headers[2], valuesApp));
@@ -82,6 +79,30 @@ public class OverviewSettingsPanel {
return cursor;
}
+ private String[] getValues() {
+ Resources res = mLauncher.getResources();
+ ArrayList<String> values = new ArrayList<String>(Arrays.asList(new String[]{
+ res.getString(R.string.home_screen_search_text),
+ res.getString(R.string.scroll_effect_text),
+ res.getString(R.string.icon_labels),
+ res.getString(R.string.scrolling_wallpaper),
+ res.getString(R.string.grid_size_text)}));
+
+ // Optionally add additional value based on setting
+ boolean remoteAppsEnabled = SettingsProvider.getBoolean(mLauncher, null,
+ R.bool.preferences_interface_homescreen_remote_folder_default);
+ if (remoteAppsEnabled) {
+ String remoteAppsName = RemoteFolderManager.getFeatureTitle(res);
+ if (remoteAppsName != null) {
+ values.add(remoteAppsName);
+ }
+ }
+
+ String[] valuesArr = new String[values.size()];
+ values.toArray(valuesArr);
+ return valuesArr;
+ }
+
// One time View setup
public void initializeViews() {
mOverviewPanel.setAlpha(0f);
@@ -169,14 +190,8 @@ public class OverviewSettingsPanel {
mSettingsAdapter.changeCursor(0, createCursor(res
.getString(R.string.home_screen_settings), new String[]{}));
} else {
- String[] values = new String[] {
- res.getString(R.string.home_screen_search_text),
- res.getString(R.string.scroll_effect_text),
- res.getString(R.string.icon_labels),
- res.getString(R.string.scrolling_wallpaper),
- res.getString(R.string.grid_size_text)};
mSettingsAdapter.changeCursor(0, createCursor(res
- .getString(R.string.home_screen_settings), values));
+ .getString(R.string.home_screen_settings), getValues()));
}
// Make sure overview panel is drawn above apps customize and collapsed
@@ -192,7 +207,6 @@ public class OverviewSettingsPanel {
mSettingsAdapter.notifyDataSetInvalidated();
}
-
class SettingsSimplePanelSlideListener extends SlidingUpPanelLayout.SimplePanelSlideListener {
ImageView mAnimatedArrow;
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 01f79314e..288030d9e 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -85,7 +85,7 @@ public class ShortcutInfo extends ItemInfo {
/**
* The application icon.
*/
- private Bitmap mIcon;
+ Bitmap mIcon;
/**
* Indicates that the icon is disabled due to safe mode restrictions.
@@ -243,6 +243,14 @@ public class ShortcutInfo extends ItemInfo {
return (status & flag) != 0;
}
+ /**
+ * Check if this shortcut has a specific flag.
+ * @param flag flag to check.
+ * @return true if the flag is present, false otherwise.
+ */
+ public boolean hasFlag(int flag) {
+ return (flags & flag) != 0;
+ }
public final boolean isPromise() {
return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINTALL_ICON);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 8fe2e841b..5eecf1b19 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -36,14 +36,14 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Paint.Style;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -627,4 +627,15 @@ public final class Utilities {
return false;
}
}
+
+ public static boolean isNetworkConnected(Context context) {
+ ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
+ return activeNetwork != null && activeNetwork.isConnected();
+ }
+
+ public static boolean isConnectedToWiFi(Context context) {
+ ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ return connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 71407b9fc..e98f12f6e 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -31,10 +31,7 @@ import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -81,7 +78,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@@ -398,6 +394,13 @@ public class Workspace extends SmoothPagedView
}
}
+ /**
+ * @return A {@link Set} of {@link Long}s representing ids of the workspace screens
+ */
+ public Set<Long> getWorkspaceScreenIds() {
+ return mWorkspaceScreens.keySet();
+ }
+
// estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
// dimension if unsuccessful
public int[] estimateItemSize(int hSpan, int vSpan,
@@ -4460,6 +4463,7 @@ public class Workspace extends SmoothPagedView
}
if (cellLayout != null) {
cellLayout.onDropChild(mDragInfo.cell);
+ cellLayout.setUseTempCoords(false);
}
}
if ((d.cancelled || (beingCalledAfterUninstall && !mUninstallSuccessful))
diff --git a/src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java b/src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java
index df9a1f05b..a9364d49f 100644
--- a/src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java
+++ b/src/com/android/launcher3/list/SettingsPinnedHeaderAdapter.java
@@ -132,6 +132,14 @@ public class SettingsPinnedHeaderAdapter extends PinnedHeaderListAdapter {
case 4:
updateDynamicGridSizeSettingsItem(v);
break;
+ case 5:
+ current = SettingsProvider.getBoolean(mContext,
+ SettingsProvider.SETTINGS_UI_HOMESCREEN_REMOTE_FOLDER,
+ R.bool.preferences_interface_homescreen_remote_folder_default);
+ state = current ? res.getString(R.string.setting_state_on)
+ : res.getString(R.string.setting_state_off);
+ ((TextView) v.findViewById(R.id.item_state)).setText(state);
+ break;
default:
((TextView) v.findViewById(R.id.item_state)).setText("");
}
@@ -308,7 +316,12 @@ public class SettingsPinnedHeaderAdapter extends PinnedHeaderListAdapter {
case 4:
mLauncher.onClickDynamicGridSizeButton();
break;
-
+ case 5:
+ boolean newValue = onSettingsBooleanChanged(v,
+ SettingsProvider.SETTINGS_UI_HOMESCREEN_REMOTE_FOLDER,
+ R.bool.preferences_interface_homescreen_remote_folder_default);
+ mLauncher.getRemoteFolderManager().onSettingChanged(newValue);
+ break;
}
break;
case OverviewSettingsPanel.DRAWER_SETTINGS_POSITION:
@@ -372,7 +385,7 @@ public class SettingsPinnedHeaderAdapter extends PinnedHeaderListAdapter {
R.bool.preferences_interface_homescreen_search_default);
}
- private void onSettingsBooleanChanged(View v, String key, int res) {
+ private boolean onSettingsBooleanChanged(View v, String key, int res) {
boolean current = SettingsProvider.getBoolean(
mContext, key, res);
@@ -384,6 +397,8 @@ public class SettingsPinnedHeaderAdapter extends PinnedHeaderListAdapter {
R.string.setting_state_off) : mLauncher.getResources().getString(
R.string.setting_state_on);
((TextView) v.findViewById(R.id.item_state)).setText(state);
+
+ return !current;
}
private void onIconLabelsBooleanChanged(View v, String key, int res) {
diff --git a/src/com/android/launcher3/settings/SettingsProvider.java b/src/com/android/launcher3/settings/SettingsProvider.java
index 042053cef..841fa3e2a 100644
--- a/src/com/android/launcher3/settings/SettingsProvider.java
+++ b/src/com/android/launcher3/settings/SettingsProvider.java
@@ -31,6 +31,7 @@ public final class SettingsProvider {
public static final String SETTINGS_UI_HOMESCREEN_SCROLLING_WALLPAPER_SCROLL = "ui_homescreen_scrolling_wallpaper_scroll";
public static final String SETTINGS_UI_HOMESCREEN_SCROLLING_PAGE_OUTLINES = "ui_homescreen_scrolling_page_outlines";
public static final String SETTINGS_UI_HOMESCREEN_SCROLLING_FADE_ADJACENT = "ui_homescreen_scrolling_fade_adjacent";
+ public static final String SETTINGS_UI_HOMESCREEN_REMOTE_FOLDER = "ui_homescreen_remote_folder";
public static final String SETTINGS_UI_DYNAMIC_GRID_SIZE = "ui_dynamic_grid_size";
public static final String SETTINGS_UI_HOMESCREEN_ROWS = "ui_homescreen_rows";
public static final String SETTINGS_UI_HOMESCREEN_COLUMNS = "ui_homescreen_columns";
diff --git a/src/com/android/launcher3/stats/LauncherStats.java b/src/com/android/launcher3/stats/LauncherStats.java
index e1dd1bbc6..5e8cb83d5 100644
--- a/src/com/android/launcher3/stats/LauncherStats.java
+++ b/src/com/android/launcher3/stats/LauncherStats.java
@@ -16,12 +16,12 @@
package com.android.launcher3.stats;
+import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
-import com.android.launcher3.LauncherApplication;
import com.android.launcher3.stats.internal.db.DatabaseHelper;
import com.android.launcher3.stats.internal.model.TrackingEvent;
@@ -41,6 +41,9 @@ public class LauncherStats {
public static final String ORIGIN_APPDRAWER = "appdrawer";
public static final String ORIGIN_TREB_LONGPRESS = "trebuchet_longpress";
public static final String ORIGIN_CHOOSER = "theme_chooser";
+ public static final String ORIGIN_SETTINGS = "settings";
+ public static final String ORIGIN_DRAG_DROP = "drag_drop";
+ public static final String ORIGIN_FOLDER = "folder";
private static void log(String msg) throws IllegalArgumentException {
if (TextUtils.isEmpty(msg)) {
@@ -101,17 +104,16 @@ public class LauncherStats {
private static LauncherStats sInstance = null;
// Members
- private static WriteHandlerThread sHandlerThread = new WriteHandlerThread();
+ private static WriteHandlerThread sHandlerThread;
private static WriteHandler sWriteHandler;
private static DatabaseHelper sDatabaseHelper;
- private LauncherApplication mApplication;
/**
* Send a message to the handler to store event data
*
* @param trackingEvent {@link TrackingEvent}
*/
- private void sendStoreEventMessage(TrackingEvent trackingEvent) {
+ protected void sendStoreEventMessage(TrackingEvent trackingEvent) {
log("Sending tracking event to handler: " + trackingEvent);
Message msg = new Message();
msg.what = MSG_STORE_EVENT;
@@ -134,32 +136,37 @@ public class LauncherStats {
}
/**
+ * Used only for overlay extensions
+ */
+ protected LauncherStats() { }
+
+ /**
* Constructor
*
- * @param application {@link LauncherApplication} not null!
+ * @param context {@link Context} not null!
* @throws IllegalArgumentException {@link IllegalArgumentException}
*/
- private LauncherStats(LauncherApplication application) throws IllegalArgumentException {
- if (application == null) {
- throw new IllegalArgumentException("'application' cannot be null!");
+ private LauncherStats(Context context) throws IllegalArgumentException {
+ if (context == null) {
+ throw new IllegalArgumentException("'context' cannot be null!");
}
- mApplication = application;
- sDatabaseHelper = new DatabaseHelper(application);
+ sDatabaseHelper = new DatabaseHelper(context);
+ sHandlerThread = new WriteHandlerThread();
sHandlerThread.start();
sWriteHandler = new WriteHandler();
}
/**
- * Creates a singleton instance of the stats utility
+ * Gets a singleton instance of the stats utility
*
- * @param application {@link LauncherApplication} not null!
+ * @param context {@link Context} not null!
* @return {@link LauncherStats}
* @throws IllegalArgumentException {@link IllegalArgumentException}
*/
- public static LauncherStats createInstance(LauncherApplication application)
+ public static LauncherStats getInstance(Context context)
throws IllegalArgumentException {
if (sInstance == null) {
- sInstance = new LauncherStats(application);
+ sInstance = new LauncherStats(context);
}
return sInstance;
}
diff --git a/src/com/android/launcher3/stats/internal/model/TrackingEvent.java b/src/com/android/launcher3/stats/internal/model/TrackingEvent.java
index 91a9017be..a44d3f148 100644
--- a/src/com/android/launcher3/stats/internal/model/TrackingEvent.java
+++ b/src/com/android/launcher3/stats/internal/model/TrackingEvent.java
@@ -51,6 +51,14 @@ public class TrackingEvent {
WALLPAPER_CHANGE,
HOMESCREEN_PAGE,
WIDGET,
+
+ // Remote folder specific
+ REMOTE_FOLDER_DISABLED,
+ REMOTE_FOLDER_OPENED,
+ REMOTE_FOLDER_INFO_OPENED,
+ REMOTE_APP_OPENED,
+ REMOTE_APP_INSTALLED,
+ REMOTE_SYNC_TIME
}
public static final String KEY_ORIGIN = TrackingBundle.KEY_METADATA_ORIGIN;