Merge "Stop animating highlighted page border in spring-loaded mode." into ub-launcher3-calgary
diff --git a/Android.mk b/Android.mk
index 0773869..e42a463 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,7 +26,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
libWallpaperPicker \
android-support-v4 \
- android-support-v7-recyclerview
+ android-support-v7-recyclerview \
+ android-support-v7-palette
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-proto-files-under, protos)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 418b1d2..80ffa43 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -141,6 +141,11 @@
</intent-filter>
</receiver>
+ <service android:name=".dynamicui.ColorExtractionService"
+ android:exported="false"
+ android:process=":wallpaper_chooser">
+ </service>
+
<!-- The settings provider contains Home's data, like the workspace favorites -->
<provider
android:name="com.android.launcher3.LauncherProvider"
diff --git a/build.gradle b/build.gradle
index 6620c10..2306744 100644
--- a/build.gradle
+++ b/build.gradle
@@ -52,12 +52,14 @@
dependencies {
compile 'com.android.support:support-v4:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.1'
+ compile 'com.android.support:palette-v7:23.2.0'
compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-2'
compile project(":WallpaperPicker-Lib")
testCompile 'junit:junit:4.12'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
+ androidTestCompile 'com.android.support:support-annotations:23.2.0'
}
protobuf {
diff --git a/res/drawable-hdpi/ic_setting_pressed.png b/res/drawable-hdpi/ic_setting_pressed.png
deleted file mode 100644
index b86fce1..0000000
--- a/res/drawable-hdpi/ic_setting_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_wallpaper_pressed.png b/res/drawable-hdpi/ic_wallpaper_pressed.png
deleted file mode 100644
index 4bb1958..0000000
--- a/res/drawable-hdpi/ic_wallpaper_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_widget_pressed.png b/res/drawable-hdpi/ic_widget_pressed.png
deleted file mode 100644
index 7f31ab3..0000000
--- a/res/drawable-hdpi/ic_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_setting_pressed.png b/res/drawable-mdpi/ic_setting_pressed.png
deleted file mode 100644
index 018bea3..0000000
--- a/res/drawable-mdpi/ic_setting_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_wallpaper_pressed.png b/res/drawable-mdpi/ic_wallpaper_pressed.png
deleted file mode 100644
index 08794d9..0000000
--- a/res/drawable-mdpi/ic_wallpaper_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_widget_pressed.png b/res/drawable-mdpi/ic_widget_pressed.png
deleted file mode 100644
index 634b415..0000000
--- a/res/drawable-mdpi/ic_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_setting_pressed.png b/res/drawable-xhdpi/ic_setting_pressed.png
deleted file mode 100644
index 949373f..0000000
--- a/res/drawable-xhdpi/ic_setting_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_wallpaper_pressed.png b/res/drawable-xhdpi/ic_wallpaper_pressed.png
deleted file mode 100644
index e1e291d..0000000
--- a/res/drawable-xhdpi/ic_wallpaper_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_widget_pressed.png b/res/drawable-xhdpi/ic_widget_pressed.png
deleted file mode 100644
index 1dcaf37..0000000
--- a/res/drawable-xhdpi/ic_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_setting_pressed.png b/res/drawable-xxhdpi/ic_setting_pressed.png
deleted file mode 100644
index d78cad6..0000000
--- a/res/drawable-xxhdpi/ic_setting_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_wallpaper_pressed.png b/res/drawable-xxhdpi/ic_wallpaper_pressed.png
deleted file mode 100644
index 52c92cb..0000000
--- a/res/drawable-xxhdpi/ic_wallpaper_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_widget_pressed.png b/res/drawable-xxhdpi/ic_widget_pressed.png
deleted file mode 100644
index 0c9b02a..0000000
--- a/res/drawable-xxhdpi/ic_widget_pressed.png
+++ /dev/null
Binary files differ
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
index f9ca01b..be16c89 100644
--- a/res/values-sw600dp-land/dimens.xml
+++ b/res/values-sw600dp-land/dimens.xml
@@ -18,4 +18,7 @@
<!-- QSB -->
<dimen name="toolbar_button_vertical_padding">12dip</dimen>
<dimen name="toolbar_button_horizontal_padding">20dip</dimen>
+
+<!-- Container -->
+ <dimen name="container_max_width">736dp</dimen>
</resources>
diff --git a/res/values-sw768dp-port/dimens.xml b/res/values-sw768dp-port/dimens.xml
new file mode 100644
index 0000000..6fb2bf6
--- /dev/null
+++ b/res/values-sw768dp-port/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+<!-- Container -->
+ <dimen name="container_max_width">736dp</dimen>
+</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7d8f6f6..281de08 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -69,6 +69,7 @@
<item name="container_margin" format="fraction" type="fraction">0%</item>
<dimen name="container_min_margin">8dp</dimen>
+ <dimen name="container_max_width">0dp</dimen>
<!-- All Apps -->
<dimen name="all_apps_button_scale_down">0dp</dimen>
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index 51a97b9..d0cacd3 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -18,16 +18,12 @@
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
-import com.android.launcher3.config.ProviderConfig;
-
/**
* A base container view, which supports resizing.
*/
@@ -52,9 +48,7 @@
super(context, attrs, defStyleAttr);
int width = ((Launcher) context).getDeviceProfile().availableWidthPx;
- mHorizontalPadding = Math.max(
- getResources().getDimensionPixelSize(R.dimen.container_min_margin),
- (int) getResources().getFraction(R.fraction.container_margin, width, 1));
+ mHorizontalPadding = DeviceProfile.getContainerPadding(context, width);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BaseContainerView, defStyleAttr, 0);
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 6426ec2..baf5e1f 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -511,6 +511,9 @@
canvas.save();
canvas.translate(mTempLocation[0], mTempLocation[1]);
bg.drawBackground(canvas, mFolderBgPaint);
+ if (!bg.isClipping) {
+ bg.drawBackgroundStroke(canvas, mFolderBgPaint);
+ }
canvas.restore();
}
@@ -530,11 +533,13 @@
for (int i = 0; i < mFolderBackgrounds.size(); i++) {
FolderIcon.PreviewBackground bg = mFolderBackgrounds.get(i);
- cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation);
- canvas.save();
- canvas.translate(mTempLocation[0], mTempLocation[1]);
- bg.drawBackgroundStroke(canvas, mFolderBgPaint);
- canvas.restore();
+ if (bg.isClipping) {
+ cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation);
+ canvas.save();
+ canvas.translate(mTempLocation[0], mTempLocation[1]);
+ bg.drawBackgroundStroke(canvas, mFolderBgPaint);
+ canvas.restore();
+ }
}
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 7c6f39e..9ab5611 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -594,4 +594,19 @@
? Math.min(widthPx, heightPx)
: Math.max(widthPx, heightPx);
}
+
+
+ public static final int getContainerPadding(Context context, int availableWidth) {
+ Resources res = context.getResources();
+
+ int maxSize = res.getDimensionPixelSize(R.dimen.container_max_width);
+ int minMargin = res.getDimensionPixelSize(R.dimen.container_min_margin);
+
+ if (maxSize > 0) {
+ return Math.max(minMargin, (availableWidth - maxSize) / 2);
+ } else {
+ return Math.max(minMargin,
+ (int) res.getFraction(R.fraction.container_margin, availableWidth, 1));
+ }
+ }
}
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 861a935..6c9d969 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -69,12 +69,12 @@
*
* @param item
*/
- public void add(ShortcutInfo item) {
+ public void add(ShortcutInfo item, boolean animate) {
contents.add(item);
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onAdd(item);
}
- itemsChanged();
+ itemsChanged(animate);
}
/**
@@ -82,12 +82,12 @@
*
* @param item
*/
- public void remove(ShortcutInfo item) {
+ public void remove(ShortcutInfo item, boolean animate) {
contents.remove(item);
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onRemove(item);
}
- itemsChanged();
+ itemsChanged(animate);
}
public void setTitle(CharSequence title) {
@@ -115,9 +115,9 @@
}
}
- void itemsChanged() {
+ public void itemsChanged(boolean animate) {
for (int i = 0; i < listeners.size(); i++) {
- listeners.get(i).onItemsChanged();
+ listeners.get(i).onItemsChanged(animate);
}
}
@@ -131,7 +131,7 @@
public void onAdd(ShortcutInfo item);
public void onRemove(ShortcutInfo item);
public void onTitleChanged(CharSequence title);
- public void onItemsChanged();
+ public void onItemsChanged(boolean animate);
}
@Override
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b16a650..445831c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -84,6 +84,7 @@
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.animation.OvershootInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.Advanceable;
@@ -105,6 +106,7 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dynamicui.ExtractedColors;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.logging.LoggerUtils;
@@ -137,7 +139,8 @@
*/
public class Launcher extends Activity
implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
- View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener {
+ View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener,
+ AccessibilityManager.AccessibilityStateChangeListener {
public static final String TAG = "Launcher";
static final boolean LOGD = false;
@@ -279,6 +282,7 @@
private LauncherModel mModel;
private IconCache mIconCache;
+ private ExtractedColors mExtractedColors;
@Thunk boolean mUserPresent = true;
private boolean mVisible = false;
private boolean mHasFocus = false;
@@ -286,8 +290,6 @@
private LauncherClings mClings;
- private static LongArrayMap<FolderInfo> sFolders = new LongArrayMap<>();
-
private View.OnTouchListener mHapticFeedbackTouchListener;
// Related to the auto-advancing of widgets
@@ -447,6 +449,11 @@
app.getInvariantDeviceProfile().portraitProfile.setSearchBarHeight(getSearchBarHeight());
setupViews();
mDeviceProfile.layout(this);
+ mExtractedColors = new ExtractedColors();
+ loadExtractedColorsAndColorItems();
+
+ ((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
+ .addAccessibilityStateChangeListener(this);
lockAllApps();
@@ -509,6 +516,18 @@
}
}
+ @Override
+ public void onExtractedColorsChanged() {
+ loadExtractedColorsAndColorItems();
+ }
+
+ private void loadExtractedColorsAndColorItems() {
+ if (mExtractedColors != null) {
+ mExtractedColors.load(this);
+ // TODO: pass mExtractedColors to interested items such as hotseat.
+ }
+ }
+
private LauncherCallbacks mLauncherCallbacks;
public void onPostCreate(Bundle savedInstanceState) {
@@ -997,7 +1016,7 @@
mPaused = false;
if (mRestoring || mOnResumeNeedsLoad) {
setWorkspaceLoading(true);
- mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
+ mModel.startLoader(getCurrentWorkspaceScreen());
mRestoring = false;
mOnResumeNeedsLoad = false;
}
@@ -1995,6 +2014,9 @@
TextKeyListener.getInstance().release();
+ ((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
+ .removeAccessibilityStateChangeListener(this);
+
unregisterReceiver(mCloseSystemDialogsReceiver);
LauncherAnimUtils.onDestroyActivity();
@@ -2333,7 +2355,6 @@
// Update the model
LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screenId,
cellX, cellY);
- sFolders.put(folderInfo.id, folderInfo);
// Create the view
FolderIcon newFolder =
@@ -2356,9 +2377,9 @@
public boolean removeItem(View v, ItemInfo itemInfo, boolean deleteFromDb) {
if (itemInfo instanceof ShortcutInfo) {
// Remove the shortcut from the folder before removing it from launcher
- FolderInfo folderInfo = sFolders.get(itemInfo.container);
- if (folderInfo != null) {
- folderInfo.remove((ShortcutInfo) itemInfo);
+ View folderIcon = mWorkspace.getHomescreenIconByItemId(itemInfo.container);
+ if (folderIcon instanceof FolderIcon) {
+ ((FolderInfo) folderIcon.getTag()).remove((ShortcutInfo) itemInfo, true);
} else {
mWorkspace.removeWorkspaceItem(v);
}
@@ -2367,7 +2388,6 @@
}
} else if (itemInfo instanceof FolderInfo) {
final FolderInfo folderInfo = (FolderInfo) itemInfo;
- unbindFolder(folderInfo);
mWorkspace.removeWorkspaceItem(v);
if (deleteFromDb) {
LauncherModel.deleteFolderAndContentsFromDatabase(this, folderInfo);
@@ -2388,13 +2408,6 @@
}
/**
- * Unbinds any launcher references to the folder.
- */
- private void unbindFolder(FolderInfo folder) {
- sFolders.remove(folder.id);
- }
-
- /**
* Deletes the widget info and the widget id.
*/
private void deleteWidgetInfo(final LauncherAppWidgetInfo widgetInfo) {
@@ -2778,6 +2791,11 @@
return mHapticFeedbackTouchListener;
}
+ @Override
+ public void onAccessibilityStateChanged(boolean enabled) {
+ mDragLayer.onAccessibilityStateChanged(enabled);
+ }
+
public void onDragStarted(View view) {
if (isOnCustomContent()) {
// Custom content screen doesn't participate in drag and drop. If on custom
@@ -3664,6 +3682,7 @@
* @return true if we are currently paused. The caller might be able to
* skip some work in that case since we will come back again.
*/
+ @Override
public boolean setLoadOnResume() {
if (mPaused) {
if (LOGD) Log.d(TAG, "setLoadOnResume");
@@ -3677,6 +3696,7 @@
/**
* Implementation of the method from LauncherModel.Callbacks.
*/
+ @Override
public int getCurrentWorkspaceScreen() {
if (mWorkspace != null) {
return mWorkspace.getCurrentPage();
@@ -3887,21 +3907,6 @@
workspace.requestLayout();
}
- /**
- * Implementation of the method from LauncherModel.Callbacks.
- */
- public void bindFolders(final LongArrayMap<FolderInfo> folders) {
- Runnable r = new Runnable() {
- public void run() {
- bindFolders(folders);
- }
- };
- if (waitUntilResume(r)) {
- return;
- }
- sFolders = folders.clone();
- }
-
private void bindSafeModeWidget(LauncherAppWidgetInfo item) {
PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, true);
view.updateIcon(mIconCache);
@@ -4046,7 +4051,6 @@
* Restores a pending widget.
*
* @param appWidgetId The app widget id
- * @param cellInfo The position on screen where to create the widget.
*/
private void completeRestoreAppWidget(final int appWidgetId) {
LauncherAppWidgetHostView view = mWorkspace.getWidgetForAppWidgetId(appWidgetId);
@@ -4681,7 +4685,6 @@
Log.d(TAG, "mWorkspaceLoading=" + mWorkspaceLoading);
Log.d(TAG, "mRestoring=" + mRestoring);
Log.d(TAG, "mWaitingForResult=" + mWaitingForResult);
- Log.d(TAG, "sFolders.size=" + sFolders.size());
mModel.dumpState();
// TODO(hyunyoungs): add mWidgetsView.dumpState(); or mWidgetsModel.dumpState();
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index e58652b..f84e4b5 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -28,6 +28,7 @@
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.TestingUtils;
import com.android.launcher3.util.Thunk;
@@ -107,7 +108,13 @@
// For handling managed profiles
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
- filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ // For extracting colors from the wallpaper
+ if (Utilities.isNycOrAbove()) {
+ // TODO: add a broadcast entry to the manifest for pre-N.
+ filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
+ }
sContext.registerReceiver(mModel, filter);
UserManagerCompat.getInstance(sContext).enableAndResetCache();
@@ -121,6 +128,8 @@
}, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED));
}
new ConfigMonitor(sContext).register();
+
+ ExtractionUtils.startColorExtractionServiceIfNecessary(sContext);
}
/**
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 3c7366c..f2b307b 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -54,6 +54,7 @@
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.GridSizeMigrationTask;
@@ -102,7 +103,6 @@
private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
private static final long INVALID_SCREEN_ID = -1L;
- @Thunk final boolean mAppsCanBeOnRemoveableStorage;
private final boolean mOldContentProviderExists;
@Thunk final LauncherAppState mApp;
@@ -184,7 +184,6 @@
boolean forceAnimateIcons);
public void bindScreens(ArrayList<Long> orderedScreenIds);
public void bindAddScreens(ArrayList<Long> orderedScreenIds);
- public void bindFolders(LongArrayMap<FolderInfo> folders);
public void finishBindingItems();
public void bindAppWidget(LauncherAppWidgetInfo info);
public void bindAllApplications(ArrayList<AppInfo> apps);
@@ -216,7 +215,6 @@
LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {
Context context = app.getContext();
- mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();
String oldProvider = context.getString(R.string.old_launcher_provider_uri);
// This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different
// resource string.
@@ -1169,20 +1167,8 @@
@Override
public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,
boolean replacing) {
- if (!replacing) {
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,
- user));
- if (mAppsCanBeOnRemoveableStorage) {
- // Only rebind if we support removable storage. It catches the
- // case where
- // apps on the external sd card need to be reloaded
- startLoaderFromBackground();
- }
- } else {
- // If we are replacing then just update the packages in the list
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,
- packageNames, user));
- }
+ enqueuePackageUpdated(
+ new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE, packageNames, user));
}
@Override
@@ -1230,13 +1216,16 @@
|| LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
UserManagerCompat.getInstance(context).enableAndResetCache();
forceReload();
- } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
+ } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action) ||
+ LauncherAppsCompat.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
UserHandleCompat user = UserHandleCompat.fromIntent(intent);
if (user != null) {
enqueuePackageUpdated(new PackageUpdatedTask(
PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE,
new String[0], user));
}
+ } else if (Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
+ ExtractionUtils.startColorExtractionServiceIfNecessary(context);
}
}
@@ -1266,17 +1255,13 @@
* of doing it now.
*/
public void startLoaderFromBackground() {
- boolean runLoader = false;
Callbacks callbacks = getCallback();
if (callbacks != null) {
// Only actually run the loader if they're not paused.
if (!callbacks.setLoadOnResume()) {
- runLoader = true;
+ startLoader(callbacks.getCurrentWorkspaceScreen());
}
}
- if (runLoader) {
- startLoader(PagedView.INVALID_RESTORE_PAGE);
- }
}
/**
@@ -1313,7 +1298,7 @@
// If there is already one running, tell it to stop.
stopLoaderLocked();
- mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);
+ mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags, synchronousBindPage);
if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
&& mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) {
mLoaderTask.runBindSynchronousPage(synchronousBindPage);
@@ -1367,14 +1352,17 @@
*/
private class LoaderTask implements Runnable {
private Context mContext;
+ private int mPageToBindFirst;
+
@Thunk boolean mIsLoadingAndBindingWorkspace;
private boolean mStopped;
@Thunk boolean mLoadAndBindStepFinished;
private int mFlags;
- LoaderTask(Context context, int flags) {
+ LoaderTask(Context context, int flags, int pageToBindFirst) {
mContext = context;
mFlags = flags;
+ mPageToBindFirst = pageToBindFirst;
}
private void loadAndBindWorkspace() {
@@ -1396,7 +1384,7 @@
}
// Bind the workspace
- bindWorkspace(-1);
+ bindWorkspace(mPageToBindFirst);
}
private void waitForIdle() {
@@ -1998,7 +1986,7 @@
// Item is in a user folder
FolderInfo folderInfo =
findOrMakeFolder(sBgFolders, container);
- folderInfo.add(info);
+ folderInfo.add(info, false);
break;
}
sBgItemsIdMap.put(info.id, info);
@@ -2360,29 +2348,6 @@
}
}
- /** Filters the set of folders which are on the specified screen. */
- private void filterCurrentFolders(long currentScreenId,
- LongArrayMap<ItemInfo> itemsIdMap,
- LongArrayMap<FolderInfo> folders,
- LongArrayMap<FolderInfo> currentScreenFolders,
- LongArrayMap<FolderInfo> otherScreenFolders) {
-
- int total = folders.size();
- for (int i = 0; i < total; i++) {
- long id = folders.keyAt(i);
- FolderInfo folder = folders.valueAt(i);
-
- ItemInfo info = itemsIdMap.get(id);
- if (info == null || folder == null) continue;
- if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- info.screenId == currentScreenId) {
- currentScreenFolders.put(id, folder);
- } else {
- otherScreenFolders.put(id, folder);
- }
- }
- }
-
/** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to
* right) */
private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {
@@ -2439,7 +2404,6 @@
private void bindWorkspaceItems(final Callbacks oldCallbacks,
final ArrayList<ItemInfo> workspaceItems,
final ArrayList<LauncherAppWidgetInfo> appWidgets,
- final LongArrayMap<FolderInfo> folders,
final Executor executor) {
// Bind the workspace items
@@ -2460,19 +2424,6 @@
executor.execute(r);
}
- // Bind the folders
- if (!folders.isEmpty()) {
- final Runnable r = new Runnable() {
- public void run() {
- Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- if (callbacks != null) {
- callbacks.bindFolders(folders);
- }
- }
- };
- executor.execute(r);
- }
-
// Bind the widgets, one at a time
N = appWidgets.size();
for (int i = 0; i < N; i++) {
@@ -2506,21 +2457,14 @@
}
// Save a copy of all the bg-thread collections
- ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();
- ArrayList<LauncherAppWidgetInfo> appWidgets =
- new ArrayList<LauncherAppWidgetInfo>();
- ArrayList<Long> orderedScreenIds = new ArrayList<Long>();
-
- final LongArrayMap<FolderInfo> folders;
- final LongArrayMap<ItemInfo> itemsIdMap;
+ ArrayList<ItemInfo> workspaceItems = new ArrayList<>();
+ ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
+ ArrayList<Long> orderedScreenIds = new ArrayList<>();
synchronized (sBgLock) {
workspaceItems.addAll(sBgWorkspaceItems);
appWidgets.addAll(sBgAppWidgets);
orderedScreenIds.addAll(sBgWorkspaceScreens);
-
- folders = sBgFolders.clone();
- itemsIdMap = sBgItemsIdMap.clone();
}
final boolean isLoadingSynchronously =
@@ -2540,21 +2484,15 @@
unbindWorkspaceItemsOnMainThread();
// Separate the items that are on the current screen, and all the other remaining items
- ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();
- ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();
- ArrayList<LauncherAppWidgetInfo> currentAppWidgets =
- new ArrayList<LauncherAppWidgetInfo>();
- ArrayList<LauncherAppWidgetInfo> otherAppWidgets =
- new ArrayList<LauncherAppWidgetInfo>();
- LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();
- LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();
+ ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
+ ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
+ ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
+ ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,
otherWorkspaceItems);
filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,
otherAppWidgets);
- filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,
- otherFolders);
sortWorkspaceItemsSpatially(currentWorkspaceItems);
sortWorkspaceItemsSpatially(otherWorkspaceItems);
@@ -2574,8 +2512,7 @@
Executor mainExecutor = new DeferredMainThreadExecutor();
// Load items on the current page.
- bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,
- currentFolders, mainExecutor);
+ bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, mainExecutor);
// In case of isLoadingSynchronously, only bind the first screen, and defer binding the
// remaining screens after first onDraw is called. This ensures that the first screen
@@ -2584,8 +2521,7 @@
final Executor deferredExecutor = isLoadingSynchronously ?
new ViewOnDrawExecutor(mHandler) : mainExecutor;
- bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets,
- otherFolders, deferredExecutor);
+ bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, deferredExecutor);
// Tell the workspace that we're done binding items
r = new Runnable() {
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 207121b..f076094 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -53,6 +53,7 @@
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.NoLocaleSqliteContext;
import com.android.launcher3.util.Thunk;
@@ -257,7 +258,7 @@
}
@Override
- public Bundle call(String method, String arg, Bundle extras) {
+ public Bundle call(String method, final String arg, final Bundle extras) {
if (Binder.getCallingUid() != Process.myUid()) {
return null;
}
@@ -277,13 +278,19 @@
return result;
}
case LauncherSettings.Settings.METHOD_SET_BOOLEAN: {
- boolean value = extras.getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
+ final boolean value = extras.getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
Utilities.getPrefs(getContext()).edit().putBoolean(arg, value).apply();
- synchronized (LISTENER_LOCK) {
- if (mListener != null) {
- mListener.onSettingsChanged(arg, value);
+ new MainThreadExecutor().execute(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (LISTENER_LOCK) {
+ if (mListener != null) {
+ mListener.onSettingsChanged(arg, value);
+ }
+ }
+
}
- }
+ });
if (extras.getBoolean(LauncherSettings.Settings.NOTIFY_BACKUP)) {
LauncherBackupAgentHelper.dataChanged(getContext());
}
@@ -291,6 +298,29 @@
result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, value);
return result;
}
+ case LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID: {
+ String extractedColors = extras.getString(
+ LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS);
+ int wallpaperId = extras.getInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID);
+ Utilities.getPrefs(getContext()).edit()
+ .putString(ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, extractedColors)
+ .putInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, wallpaperId)
+ .apply();
+ new MainThreadExecutor().execute(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (LISTENER_LOCK) {
+ if (mListener != null) {
+ mListener.onExtractedColorsChanged();
+ }
+ }
+
+ }
+ });
+ Bundle result = new Bundle();
+ result.putString(LauncherSettings.Settings.EXTRA_VALUE, extractedColors);
+ return result;
+ }
case LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG: {
clearFlagEmptyDbCreated();
return null;
diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java
index 1b78e9c..2d2da6e 100644
--- a/src/com/android/launcher3/LauncherProviderChangeListener.java
+++ b/src/com/android/launcher3/LauncherProviderChangeListener.java
@@ -11,5 +11,7 @@
public void onSettingsChanged(String settings, boolean value);
+ public void onExtractedColorsChanged();
+
public void onAppWidgetHostReset();
}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index fb53068..0c16287 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -339,6 +339,11 @@
public static final String METHOD_LOAD_DEFAULT_FAVORITES = "load_default_favorites";
public static final String METHOD_MIGRATE_LAUNCHER2_SHORTCUTS = "migrate_l2_shortcuts";
+ public static final String METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID =
+ "set_extracted_colors_and_wallpaper_id_setting";
+ public static final String EXTRA_EXTRACTED_COLORS = "extra_extractedColors";
+ public static final String EXTRA_WALLPAPER_ID = "extra_wallpaperId";
+
public static final String EXTRA_VALUE = "value";
public static final String EXTRA_DEFAULT_VALUE = "default_value";
// Extra for set_boolean method to also notify the backup manager of the change.
diff --git a/src/com/android/launcher3/PinchToOverviewListener.java b/src/com/android/launcher3/PinchToOverviewListener.java
index 74e6b39..f32c845 100644
--- a/src/com/android/launcher3/PinchToOverviewListener.java
+++ b/src/com/android/launcher3/PinchToOverviewListener.java
@@ -33,6 +33,11 @@
public class PinchToOverviewListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private static final float OVERVIEW_PROGRESS = 0f;
private static final float WORKSPACE_PROGRESS = 1f;
+ /**
+ * The velocity threshold at which a pinch will be completed instead of canceled,
+ * even if the first threshold has not been passed. Measured in progress / millisecond
+ */
+ private static final float FLING_VELOCITY = 0.003f;
private ScaleGestureDetector mPinchDetector;
private Launcher mLauncher;
@@ -110,17 +115,20 @@
public void onScaleEnd(ScaleGestureDetector detector) {
super.onScaleEnd(detector);
+ float progressVelocity = mProgressDelta / mTimeDelta;
float passedThreshold = mThresholdManager.getPassedThreshold();
+ boolean isFling = mWorkspace.isInOverviewMode() && progressVelocity >= FLING_VELOCITY
+ || !mWorkspace.isInOverviewMode() && progressVelocity <= -FLING_VELOCITY;
+ boolean shouldCancelPinch = !isFling && passedThreshold < PinchThresholdManager.THRESHOLD_ONE;
// If we are going towards overview, mPreviousProgress is how much further we need to
// go, since it is going from 1 to 0. If we are going to workspace, we want
// 1 - mPreviousProgress.
float remainingProgress = mPreviousProgress;
- if (mWorkspace.isInOverviewMode() || passedThreshold < PinchThresholdManager.THRESHOLD_ONE) {
+ if (mWorkspace.isInOverviewMode() || shouldCancelPinch) {
remainingProgress = 1f - mPreviousProgress;
}
- int duration = computeDuration(remainingProgress, mProgressDelta, mTimeDelta);
-
- if (passedThreshold < PinchThresholdManager.THRESHOLD_ONE) {
+ int duration = computeDuration(remainingProgress, progressVelocity);
+ if (shouldCancelPinch) {
cancelPinch(mPreviousProgress, duration);
} else if (passedThreshold < PinchThresholdManager.THRESHOLD_THREE) {
float toProgress = mWorkspace.isInOverviewMode() ?
@@ -138,8 +146,8 @@
* Compute the amount of time required to complete the transition based on the current pinch
* speed. If this time is too long, instead return the normal duration, ignoring the speed.
*/
- private int computeDuration(float remainingProgress, float progressDelta, long timeDelta) {
- float progressSpeed = Math.abs(progressDelta) / timeDelta;
+ private int computeDuration(float remainingProgress, float progressVelocity) {
+ float progressSpeed = Math.abs(progressVelocity);
int remainingMillis = (int) (remainingProgress / progressSpeed);
return Math.min(remainingMillis, mAnimationManager.getNormalOverviewTransitionDuration());
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index bd5cd8a..f04244f 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -219,7 +219,7 @@
public static final int REORDER_TIMEOUT = 350;
private final Alarm mFolderCreationAlarm = new Alarm();
private final Alarm mReorderAlarm = new Alarm();
- private FolderIcon.PreviewBackground mFolderCreateBg = new FolderIcon.PreviewBackground();
+ private FolderIcon.PreviewBackground mFolderCreateBg;
private FolderIcon mDragOverFolderIcon = null;
private boolean mCreateUserFolderOnDrop = false;
private boolean mAddToExistingFolderOnDrop = false;
@@ -2878,7 +2878,9 @@
}
private void cleanupFolderCreation() {
- mFolderCreateBg.animateToRest();
+ if (mFolderCreateBg != null) {
+ mFolderCreateBg.animateToRest();
+ }
mFolderCreationAlarm.setOnAlarmListener(null);
mFolderCreationAlarm.cancelAlarm();
}
@@ -3182,6 +3184,8 @@
int cellX;
int cellY;
+ FolderIcon.PreviewBackground bg = new FolderIcon.PreviewBackground();
+
public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {
this.layout = layout;
this.cellX = cellX;
@@ -3190,11 +3194,15 @@
DeviceProfile grid = mLauncher.getDeviceProfile();
BubbleTextView cell = (BubbleTextView) layout.getChildAt(cellX, cellY);
- mFolderCreateBg.setup(getResources().getDisplayMetrics(), grid, null,
+ bg.setup(getResources().getDisplayMetrics(), grid, null,
cell.getMeasuredWidth(), cell.getPaddingTop());
+
+ // The full preview background should appear behind the icon
+ bg.isClipping = false;
}
public void onAlarm(Alarm alarm) {
+ mFolderCreateBg = bg;
mFolderCreateBg.animateToAccept(layout, cellX, cellY);
layout.clearDragOutlines();
setDragMode(DRAG_MODE_CREATE_FOLDER);
@@ -3865,7 +3873,7 @@
return getFirstMatch(new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View v, View parent) {
+ public boolean evaluate(ItemInfo info, View v) {
return info != null && info.id == id;
}
});
@@ -3875,7 +3883,7 @@
return getFirstMatch(new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View v, View parent) {
+ public boolean evaluate(ItemInfo info, View v) {
return info == tag;
}
});
@@ -3885,7 +3893,7 @@
return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View v, View parent) {
+ public boolean evaluate(ItemInfo info, View v) {
return (info instanceof LauncherAppWidgetInfo) &&
((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId;
}
@@ -3896,8 +3904,8 @@
final View[] value = new View[1];
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View v, View parent) {
- if (operator.evaluate(info, v, parent)) {
+ public boolean evaluate(ItemInfo info, View v) {
+ if (operator.evaluate(info, v)) {
value[0] = v;
return true;
}
@@ -3910,7 +3918,7 @@
void clearDropTargets() {
mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View v, View parent) {
+ public boolean evaluate(ItemInfo info, View v) {
if (v instanceof DropTarget) {
mDragController.removeDropTarget((DropTarget) v);
}
@@ -4006,7 +4014,7 @@
for (FolderInfo folder : folderAppsToRemove.keySet()) {
ArrayList<ShortcutInfo> appsToRemove = folderAppsToRemove.get(folder);
for (ShortcutInfo info : appsToRemove) {
- folder.remove(info);
+ folder.remove(info, false);
}
}
@@ -4036,10 +4044,9 @@
*
* @param info info for the shortcut
* @param view view for the shortcut
- * @param parent containing folder, or null
* @return true if done, false to continue the map
*/
- public boolean evaluate(ItemInfo info, View view, View parent);
+ public boolean evaluate(ItemInfo info, View view);
}
/**
@@ -4066,12 +4073,12 @@
for (int childIdx = 0; childIdx < childCount; childIdx++) {
View child = folderChildren.get(childIdx);
info = (ItemInfo) child.getTag();
- if (op.evaluate(info, child, folder)) {
+ if (op.evaluate(info, child)) {
return;
}
}
} else {
- if (op.evaluate(info, item, null)) {
+ if (op.evaluate(info, item)) {
return;
}
}
@@ -4080,10 +4087,19 @@
}
void updateShortcuts(ArrayList<ShortcutInfo> shortcuts) {
- final HashSet<ShortcutInfo> updates = new HashSet<ShortcutInfo>(shortcuts);
+ int total = shortcuts.size();
+ final HashSet<ShortcutInfo> updates = new HashSet<ShortcutInfo>(total);
+ final HashSet<Long> folderIds = new HashSet<>();
+
+ for (int i = 0; i < total; i++) {
+ ShortcutInfo s = shortcuts.get(i);
+ updates.add(s);
+ folderIds.add(s.container);
+ }
+
mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View v, View parent) {
+ public boolean evaluate(ItemInfo info, View v) {
if (info instanceof ShortcutInfo && v instanceof BubbleTextView &&
updates.contains(info)) {
ShortcutInfo si = (ShortcutInfo) info;
@@ -4093,10 +4109,18 @@
&& ((PreloadIconDrawable) oldIcon).hasNotCompleted();
shortcut.applyFromShortcutInfo(si, mIconCache,
si.isPromise() != oldPromiseState);
+ }
+ // process all the shortcuts
+ return false;
+ }
+ });
- if (parent != null) {
- parent.invalidate();
- }
+ // Update folder icons
+ mapOverItems(MAP_NO_RECURSE, new ItemOperator() {
+ @Override
+ public boolean evaluate(ItemInfo info, View v) {
+ if (info instanceof FolderInfo && folderIds.contains(info.id)) {
+ ((FolderInfo) info).itemsChanged(false);
}
// process all the shortcuts
return false;
@@ -4114,7 +4138,7 @@
public void updateRestoreItems(final HashSet<ItemInfo> updates) {
mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View v, View parent) {
+ public boolean evaluate(ItemInfo info, View v) {
if (info instanceof ShortcutInfo && v instanceof BubbleTextView
&& updates.contains(info)) {
((BubbleTextView) v).applyState(false);
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index c699479..aa6e08e 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -174,7 +174,7 @@
Folder folder = mLauncher.getWorkspace().getOpenFolder();
mLauncher.closeFolder(folder, true);
ShortcutInfo info = (ShortcutInfo) item;
- folder.getInfo().remove(info);
+ folder.getInfo().remove(info, false);
final int[] coordinates = new int[2];
final long screenId = findSpaceOnWorkspace(item, coordinates);
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index db5b89e..bc900bc 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -35,8 +35,10 @@
"android.intent.action.MANAGED_PROFILE_ADDED";
public static final String ACTION_MANAGED_PROFILE_REMOVED =
"android.intent.action.MANAGED_PROFILE_REMOVED";
- public static final String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED =
- "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
+ public static final String ACTION_MANAGED_PROFILE_AVAILABLE =
+ "android.intent.action.MANAGED_PROFILE_AVAILABLE";
+ public static final String ACTION_MANAGED_PROFILE_UNAVAILABLE =
+ "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
public interface OnAppsChangedCallbackCompat {
void onPackageRemoved(String packageName, UserHandleCompat user);
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 58f98bf..33ce683 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -29,6 +29,7 @@
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -43,7 +44,6 @@
import com.android.launcher3.AppWidgetResizeFrame;
import com.android.launcher3.CellLayout;
-import com.android.launcher3.Hotseat;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
@@ -142,9 +142,9 @@
mLauncher = launcher;
mDragController = controller;
- if (!FeatureFlags.LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW) {
- mPinchListener = new PinchToOverviewListener(mLauncher);
- }
+ boolean isAccessibilityEnabled = ((AccessibilityManager) mLauncher.getSystemService(
+ Context.ACCESSIBILITY_SERVICE)).isEnabled();
+ onAccessibilityStateChanged(isAccessibilityEnabled);
}
@Override
@@ -152,6 +152,11 @@
return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
}
+ public void onAccessibilityStateChanged(boolean isAccessibilityEnabled) {
+ mPinchListener = FeatureFlags.LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW || isAccessibilityEnabled
+ ? null : new PinchToOverviewListener(mLauncher);
+ }
+
public void showOverlayView(View overlayView) {
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mOverlayView = overlayView;
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionService.java b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
new file mode 100644
index 0000000..95a62b9
--- /dev/null
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dynamicui;
+
+import android.app.IntentService;
+import android.app.WallpaperManager;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Bundle;
+import android.support.v7.graphics.Palette;
+
+import com.android.launcher3.LauncherProvider;
+import com.android.launcher3.LauncherSettings;
+
+/**
+ * Extracts colors from the wallpaper, and saves results to {@link LauncherProvider}.
+ */
+public class ColorExtractionService extends IntentService {
+
+ public ColorExtractionService() {
+ super("ColorExtractionService");
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
+ int wallpaperId = ExtractionUtils.getWallpaperId(wallpaperManager);
+ ExtractedColors extractedColors = new ExtractedColors();
+ if (wallpaperManager.getWallpaperInfo() != null) {
+ // We can't extract colors from live wallpapers, so just use the default color always.
+ extractedColors.updatePalette(null);
+ } else {
+ Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap();
+ Palette palette = Palette.from(wallpaper).generate();
+ extractedColors.updatePalette(palette);
+ }
+
+ // Save the extracted colors and wallpaper id to LauncherProvider.
+ String colorsString = extractedColors.encodeAsString();
+ Bundle extras = new Bundle();
+ extras.putInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID, wallpaperId);
+ extras.putString(LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS, colorsString);
+ getContentResolver().call(
+ LauncherSettings.Settings.CONTENT_URI,
+ LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID,
+ null, extras);
+ }
+}
diff --git a/src/com/android/launcher3/dynamicui/ExtractedColors.java b/src/com/android/launcher3/dynamicui/ExtractedColors.java
new file mode 100644
index 0000000..4d17ff7
--- /dev/null
+++ b/src/com/android/launcher3/dynamicui/ExtractedColors.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dynamicui;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.v7.graphics.Palette;
+import android.util.Log;
+
+import com.android.launcher3.Utilities;
+
+/**
+ * Saves and loads colors extracted from the wallpaper, as well as the associated wallpaper id.
+ */
+public class ExtractedColors {
+ private static final String TAG = "ExtractedColors";
+
+ public static final int DEFAULT_LIGHT = Color.WHITE;
+ public static final int DEFAULT_DARK = Color.BLACK;
+ public static final int DEFAULT_COLOR = DEFAULT_LIGHT;
+
+ // These color profile indices should NOT be changed, since they are used when saving and
+ // loading extracted colors. New colors should always be added at the end.
+ public static final int DEFAULT_INDEX = 0;
+ public static final int VIBRANT_INDEX = 1;
+ public static final int VIBRANT_DARK_INDEX = 2;
+ public static final int VIBRANT_LIGHT_INDEX = 3;
+ public static final int MUTED_INDEX = 4;
+ public static final int MUTED_DARK_INDEX = 5;
+ public static final int MUTED_LIGHT_INDEX = 6;
+
+ public static final int NUM_COLOR_PROFILES = 7;
+
+ private static final String COLOR_SEPARATOR = ",";
+
+ private int[] mColors;
+
+ public ExtractedColors() {
+ mColors = new int[NUM_COLOR_PROFILES];
+ }
+
+ public void setColorAtIndex(int index, int color) {
+ if (index >= 0 && index < mColors.length) {
+ mColors[index] = color;
+ } else {
+ Log.e(TAG, "Attempted to set a color at an invalid index " + index);
+ }
+ }
+
+ /**
+ * Encodes {@link #mColors} as a comma-separated String.
+ */
+ String encodeAsString() {
+ StringBuilder colorsStringBuilder = new StringBuilder();
+ for (int color : mColors) {
+ colorsStringBuilder.append(color).append(COLOR_SEPARATOR);
+ }
+ return colorsStringBuilder.toString();
+ }
+
+ /**
+ * Decodes a comma-separated String into {@link #mColors}.
+ */
+ void decodeFromString(String colorsString) {
+ String[] splitColorsString = colorsString.split(COLOR_SEPARATOR);
+ mColors = new int[splitColorsString.length];
+ for (int i = 0; i < mColors.length; i++) {
+ mColors[i] = Integer.parseInt(splitColorsString[i]);
+ }
+ }
+
+ /**
+ * Loads colors and wallpaper id from {@link Utilities#getPrefs(Context)}.
+ * These were saved there in {@link ColorExtractionService}.
+ */
+ public void load(Context context) {
+ String encodedString = Utilities.getPrefs(context).getString(
+ ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, DEFAULT_COLOR + "");
+
+ decodeFromString(encodedString);
+ }
+
+ /** @param index must be one of the index values defined at the top of this class. */
+ public int getColor(int index) {
+ if (index >= 0 && index < mColors.length) {
+ return mColors[index];
+ }
+ return DEFAULT_COLOR;
+ }
+
+ /**
+ * Updates colors based on the palette.
+ * If the palette is null, the default color is used in all cases.
+ */
+ public void updatePalette(Palette palette) {
+ if (palette == null) {
+ for (int i = 0; i < NUM_COLOR_PROFILES; i++) {
+ setColorAtIndex(i, ExtractedColors.DEFAULT_COLOR);
+ }
+ } else {
+ setColorAtIndex(ExtractedColors.DEFAULT_INDEX,
+ ExtractedColors.DEFAULT_COLOR);
+ setColorAtIndex(ExtractedColors.VIBRANT_INDEX,
+ palette.getVibrantColor(ExtractedColors.DEFAULT_COLOR));
+ setColorAtIndex(ExtractedColors.VIBRANT_DARK_INDEX,
+ palette.getDarkVibrantColor(ExtractedColors.DEFAULT_DARK));
+ setColorAtIndex(ExtractedColors.VIBRANT_LIGHT_INDEX,
+ palette.getLightVibrantColor(ExtractedColors.DEFAULT_LIGHT));
+ setColorAtIndex(ExtractedColors.MUTED_INDEX,
+ palette.getMutedColor(ExtractedColors.DEFAULT_COLOR));
+ setColorAtIndex(ExtractedColors.MUTED_DARK_INDEX,
+ palette.getDarkMutedColor(ExtractedColors.DEFAULT_DARK));
+ setColorAtIndex(ExtractedColors.MUTED_LIGHT_INDEX,
+ palette.getLightVibrantColor(ExtractedColors.DEFAULT_LIGHT));
+ }
+ }
+}
diff --git a/src/com/android/launcher3/dynamicui/ExtractionUtils.java b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
new file mode 100644
index 0000000..0b28ba6
--- /dev/null
+++ b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dynamicui;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+
+import com.android.launcher3.Utilities;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Contains helper fields and methods related to extracting colors from the wallpaper.
+ */
+public class ExtractionUtils {
+ public static final String EXTRACTED_COLORS_PREFERENCE_KEY = "pref_extractedColors";
+ public static final String WALLPAPER_ID_PREFERENCE_KEY = "pref_wallpaperId";
+
+ private static final int FLAG_SET_SYSTEM = 1 << 0; // TODO: use WallpaperManager.FLAG_SET_SYSTEM
+
+ /**
+ * Extract colors in the :wallpaper-chooser process, if the wallpaper id has changed.
+ * When the new colors are saved in the LauncherProvider,
+ * Launcher will be notified in Launcher#onSettingsChanged(String, String).
+ */
+ public static void startColorExtractionServiceIfNecessary(final Context context) {
+ // Run on a background thread, since the service is asynchronous anyway.
+ Utilities.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+ @Override
+ public void run() {
+ if (hasWallpaperIdChanged(context)) {
+ context.startService(new Intent(context, ColorExtractionService.class));
+ }
+ }
+ });
+ }
+
+ private static boolean hasWallpaperIdChanged(Context context) {
+ if (!Utilities.isNycOrAbove()) {
+ // TODO: update an id in sharedprefs in onWallpaperChanged broadcast, and read it here.
+ return false;
+ }
+ final SharedPreferences sharedPrefs = Utilities.getPrefs(context);
+ int wallpaperId = getWallpaperId(WallpaperManager.getInstance(context));
+ int savedWallpaperId = sharedPrefs.getInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, -1);
+ return wallpaperId != savedWallpaperId;
+ }
+
+ public static int getWallpaperId(WallpaperManager wallpaperManager) {
+ // TODO: use WallpaperManager#getWallpaperId(WallpaperManager.FLAG_SET_SYSTEM) directly.
+ try {
+ Method getWallpaperId = WallpaperManager.class.getMethod("getWallpaperId", int.class);
+ return (int) getWallpaperId.invoke(wallpaperManager, FLAG_SET_SYSTEM);
+ } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
+ return -1;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 087670e..09a92a9 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -300,7 +300,7 @@
mCurrentDragView = v;
mContent.removeItem(mCurrentDragView);
- mInfo.remove(mCurrentDragInfo);
+ mInfo.remove(mCurrentDragInfo, true);
mDragInProgress = true;
mItemAddedBackToSelfViaIcon = false;
}
@@ -426,8 +426,9 @@
// If our folder has too many items we prune them from the list. This is an issue
// when upgrading from the old Folders implementation which could contain an unlimited
// number of items.
+ // TODO: Remove this, as with multi-page folders, there will never be any overflow
for (ShortcutInfo item: overflow) {
- mInfo.remove(item);
+ mInfo.remove(item, false);
LauncherModel.deleteItemFromDatabase(mLauncher, item);
}
@@ -1330,7 +1331,7 @@
// Temporarily suppress the listener, as we did all the work already here.
mSuppressOnAdd = true;
- mInfo.add(si);
+ mInfo.add(si, false);
mSuppressOnAdd = false;
// Clear the drag info, as it is no longer being dragged.
mCurrentDragInfo = null;
@@ -1390,13 +1391,14 @@
return mContent.iterateOverItems(new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View view, View parent) {
+ public boolean evaluate(ItemInfo info, View view) {
return info == item;
}
});
}
- public void onItemsChanged() {
+ @Override
+ public void onItemsChanged(boolean animate) {
updateTextViewFocus();
}
@@ -1409,7 +1411,7 @@
mContent.iterateOverItems(new ItemOperator() {
@Override
- public boolean evaluate(ItemInfo info, View view, View parent) {
+ public boolean evaluate(ItemInfo info, View view) {
mItemsInReadingOrder.add(view);
return false;
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index a9b707f..d76608a 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -224,7 +224,7 @@
}
public void addItem(ShortcutInfo item) {
- mInfo.add(item);
+ mInfo.add(item, true);
}
public void onDragEnter(ItemInfo dragInfo) {
@@ -492,12 +492,16 @@
canvas.restore();
}
+ /**
+ * This object represents a FolderIcon preview background. It stores drawing / measurement
+ * information, handles drawing, and animation (accept state <--> rest state).
+ */
public static class PreviewBackground {
private float mScale = 1f;
private float mColorMultiplier = 1f;
private Path mClipPath = new Path();
private int mStrokeWidth;
- private View mInvalidateDeligate;
+ private View mInvalidateDelegate;
public int previewSize;
private int basePreviewOffsetX;
@@ -507,6 +511,10 @@
public int delegateCellX;
public int delegateCellY;
+ // When the PreviewBackground is drawn under an icon (for creating a folder) the border
+ // should not occlude the icon
+ public boolean isClipping = true;
+
// Drawing / animation configurations
private static final float ACCEPT_SCALE_FACTOR = 1.25f;
private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
@@ -519,9 +527,9 @@
ValueAnimator mScaleAnimator;
- public void setup(DisplayMetrics dm, DeviceProfile grid, View invalidateDeligate,
+ public void setup(DisplayMetrics dm, DeviceProfile grid, View invalidateDelegate,
int availableSpace, int topPadding) {
- mInvalidateDeligate = invalidateDeligate;
+ mInvalidateDelegate = invalidateDelegate;
final int previewSize = grid.folderIconSizePx;
final int previewPadding = grid.folderIconPreviewPadding;
@@ -557,8 +565,8 @@
mClipPath.reset();
mClipPath.addCircle(radius, radius, radius, Path.Direction.CW);
- if (mInvalidateDeligate != null) {
- mInvalidateDeligate.invalidate();
+ if (mInvalidateDelegate != null) {
+ mInvalidateDelegate.invalidate();
}
if (mDrawingDelegate != null) {
@@ -566,8 +574,8 @@
}
}
- void setInvalidateDeligate(View invalidateDeligate) {
- mInvalidateDeligate = invalidateDeligate;
+ void setInvalidateDelegate(View invalidateDelegate) {
+ mInvalidateDelegate = invalidateDelegate;
invalidate();
}
@@ -742,7 +750,7 @@
public void setFolderBackground(PreviewBackground bg) {
mBackground = bg;
- mBackground.setInvalidateDeligate(this);
+ mBackground.setInvalidateDelegate(this);
}
@Override
@@ -929,8 +937,9 @@
}
}
- public void onItemsChanged() {
- updateItemDrawingParams(true);
+ @Override
+ public void onItemsChanged(boolean animate) {
+ updateItemDrawingParams(animate);
invalidate();
requestLayout();
}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index c25444e..1af1485 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -454,7 +454,7 @@
for (int j = 0; j < page.getCountY(); j++) {
for (int i = 0; i < page.getCountX(); i++) {
View v = page.getChildAt(i, j);
- if ((v != null) && op.evaluate((ItemInfo) v.getTag(), v, this)) {
+ if ((v != null) && op.evaluate((ItemInfo) v.getTag(), v)) {
return v;
}
}
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index fb9bbb2..3925c40 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -188,7 +188,7 @@
@Override
public void run() {
for (ShortcutInfo info : shortcuts) {
- workFolder.add(info);
+ workFolder.add(info, false);
}
}
});
@@ -200,7 +200,7 @@
// Add all shortcuts before adding it to the UI, as an empty folder might get deleted.
for (ShortcutInfo info : mWorkFolderApps) {
- workFolder.add(info);
+ workFolder.add(info, false);
}
// Add the item to home screen and DB. This also generates an item id synchronously.