Adding support for dynamic calendar and clock icons
Change-Id: Icdba34340a27a4f6dff7310d0bf9fd29aef1330c
This commit is contained in:
parent
70d7860eae
commit
14168431bd
|
@ -40,6 +40,7 @@ import android.graphics.Matrix;
|
|||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
|
@ -66,6 +67,7 @@ import com.android.launcher3.R;
|
|||
import com.android.launcher3.util.Themes;
|
||||
import com.android.quickstep.ContentFillItemAnimator;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
|
||||
import com.android.quickstep.RecentsToActivityHelper;
|
||||
import com.android.quickstep.TaskActionController;
|
||||
import com.android.quickstep.TaskAdapter;
|
||||
|
@ -74,6 +76,7 @@ import com.android.quickstep.TaskListLoader;
|
|||
import com.android.quickstep.TaskSwipeCallback;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||
|
@ -87,7 +90,8 @@ import java.util.Optional;
|
|||
* Root view for the icon recents view. Acts as the main interface to the rest of the Launcher code
|
||||
* base.
|
||||
*/
|
||||
public final class IconRecentsView extends FrameLayout implements Insettable {
|
||||
public final class IconRecentsView extends FrameLayout
|
||||
implements Insettable, TaskVisualsChangeListener {
|
||||
|
||||
public static final FloatProperty<IconRecentsView> CONTENT_ALPHA =
|
||||
new FloatProperty<IconRecentsView>("contentAlpha") {
|
||||
|
@ -159,22 +163,6 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
|||
private AnimatorSet mLayoutAnimation;
|
||||
private final ArraySet<View> mLayingOutViews = new ArraySet<>();
|
||||
private Rect mInsets;
|
||||
private final RecentsModel.TaskThumbnailChangeListener listener = (taskId, thumbnailData) -> {
|
||||
ArrayList<TaskItemView> itemViews = getTaskViews();
|
||||
for (int i = 0, size = itemViews.size(); i < size; i++) {
|
||||
TaskItemView taskView = itemViews.get(i);
|
||||
TaskHolder taskHolder = (TaskHolder) mTaskRecyclerView.getChildViewHolder(taskView);
|
||||
Optional<Task> optTask = taskHolder.getTask();
|
||||
if (optTask.filter(task -> task.key.id == taskId).isPresent()) {
|
||||
Task task = optTask.get();
|
||||
// Update thumbnail on the task.
|
||||
task.thumbnail = thumbnailData;
|
||||
taskView.setThumbnail(thumbnailData);
|
||||
return task;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
public IconRecentsView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
@ -189,9 +177,29 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
|||
mActivity.getStatsLogManager());
|
||||
mTaskAdapter.setActionController(mTaskActionController);
|
||||
mTaskLayoutManager = new LinearLayoutManager(mContext, VERTICAL, true /* reverseLayout */);
|
||||
RecentsModel.INSTANCE.get(context).addThumbnailChangeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
|
||||
ArrayList<TaskItemView> itemViews = getTaskViews();
|
||||
for (int i = 0, size = itemViews.size(); i < size; i++) {
|
||||
TaskItemView taskView = itemViews.get(i);
|
||||
TaskHolder taskHolder = (TaskHolder) mTaskRecyclerView.getChildViewHolder(taskView);
|
||||
Optional<Task> optTask = taskHolder.getTask();
|
||||
if (optTask.filter(task -> task.key.id == taskId).isPresent()) {
|
||||
Task task = optTask.get();
|
||||
// Update thumbnail on the task.
|
||||
task.thumbnail = thumbnailData;
|
||||
taskView.setThumbnail(thumbnailData);
|
||||
return task;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskIconChanged(String pkg, UserHandle user) { }
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
@ -274,6 +282,18 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
|
|
|
@ -116,7 +116,7 @@ public class BaseIconFactory implements AutoCloseable {
|
|||
icon = createIconBitmap(new BitmapDrawable(mContext.getResources(), icon), 1f);
|
||||
}
|
||||
|
||||
return BitmapInfo.fromBitmap(icon, mDisableColorExtractor ? null : mColorExtractor);
|
||||
return BitmapInfo.of(icon, extractColor(icon));
|
||||
}
|
||||
|
||||
public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user,
|
||||
|
@ -186,7 +186,10 @@ public class BaseIconFactory implements AutoCloseable {
|
|||
} else {
|
||||
result = bitmap;
|
||||
}
|
||||
return BitmapInfo.fromBitmap(result, mDisableColorExtractor ? null : mColorExtractor);
|
||||
int color = extractColor(result);
|
||||
return icon instanceof BitmapInfo.Extender
|
||||
? ((BitmapInfo.Extender) icon).getExtendedInfo(result, color, this)
|
||||
: BitmapInfo.of(result, color);
|
||||
}
|
||||
|
||||
public Bitmap createScaledBitmapWithoutShadow(Drawable icon, boolean shrinkNonAdaptiveIcons) {
|
||||
|
@ -337,6 +340,10 @@ public class BaseIconFactory implements AutoCloseable {
|
|||
iconDpi);
|
||||
}
|
||||
|
||||
private int extractColor(Bitmap bitmap) {
|
||||
return mDisableColorExtractor ? 0 : mColorExtractor.findDominantColorByHue(bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct badge size given an icon size
|
||||
*/
|
||||
|
|
|
@ -19,12 +19,11 @@ import android.graphics.Bitmap;
|
|||
import android.graphics.Bitmap.Config;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class BitmapInfo {
|
||||
|
||||
public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8);
|
||||
public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON, null);
|
||||
public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON);
|
||||
|
||||
public final Bitmap icon;
|
||||
public final int color;
|
||||
|
@ -49,14 +48,25 @@ public class BitmapInfo {
|
|||
return of(bitmap, 0);
|
||||
}
|
||||
|
||||
public static BitmapInfo fromBitmap(@NonNull Bitmap bitmap,
|
||||
@Nullable ColorExtractor dominantColorExtractor) {
|
||||
return of(bitmap, dominantColorExtractor != null
|
||||
? dominantColorExtractor.findDominantColorByHue(bitmap)
|
||||
: 0);
|
||||
}
|
||||
|
||||
public static BitmapInfo of(@NonNull Bitmap bitmap, int color) {
|
||||
return new BitmapInfo(bitmap, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to be implemented by drawables to provide a custom BitmapInfo
|
||||
*/
|
||||
public interface Extender {
|
||||
|
||||
/**
|
||||
* Called for creating a custom BitmapInfo
|
||||
*/
|
||||
default BitmapInfo getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory) {
|
||||
return BitmapInfo.of(bitmap, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the drawable that it will be drawn directly in the UI, without any preprocessing
|
||||
*/
|
||||
default void prepareToDrawOnUi() { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -464,7 +464,7 @@ public abstract class BaseIconCache {
|
|||
return entry;
|
||||
}
|
||||
|
||||
private boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
|
||||
protected boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = mIconDb.query(
|
||||
|
|
|
@ -18,8 +18,6 @@ package com.android.launcher3.appprediction;
|
|||
|
||||
import static com.android.quickstep.InstantAppResolverImpl.COMPONENT_CLASS_MARKER;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
|
@ -29,11 +27,9 @@ import com.android.launcher3.util.ComponentKey;
|
|||
public class ComponentKeyMapper {
|
||||
|
||||
protected final ComponentKey componentKey;
|
||||
private final Context mContext;
|
||||
private final DynamicItemCache mCache;
|
||||
|
||||
public ComponentKeyMapper(Context context, ComponentKey key, DynamicItemCache cache) {
|
||||
mContext = context;
|
||||
public ComponentKeyMapper(ComponentKey key, DynamicItemCache cache) {
|
||||
componentKey = key;
|
||||
mCache = cache;
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ public class PredictionUiStateManager implements StateListener, ItemInfoUpdateRe
|
|||
key = new ComponentKey(new ComponentName(appTarget.getPackageName(),
|
||||
appTarget.getClassName()), appTarget.getUser());
|
||||
}
|
||||
state.apps.add(new ComponentKeyMapper(mContext, key, mDynamicItemCache));
|
||||
state.apps.add(new ComponentKeyMapper(key, mDynamicItemCache));
|
||||
}
|
||||
}
|
||||
updateDependencies(state);
|
||||
|
|
|
@ -60,6 +60,7 @@ import android.graphics.Typeface;
|
|||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
|
@ -105,7 +106,7 @@ import com.android.launcher3.util.ViewPool;
|
|||
import com.android.quickstep.RecentsAnimationController;
|
||||
import com.android.quickstep.RecentsAnimationTargets;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener;
|
||||
import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
import com.android.quickstep.TaskUtils;
|
||||
import com.android.quickstep.ViewUtils;
|
||||
|
@ -127,7 +128,7 @@ import java.util.function.Consumer;
|
|||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public abstract class RecentsView<T extends BaseActivity> extends PagedView implements Insettable,
|
||||
TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
|
||||
InvariantDeviceProfile.OnIDPChangeListener, TaskThumbnailChangeListener {
|
||||
InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener {
|
||||
|
||||
private static final String TAG = RecentsView.class.getSimpleName();
|
||||
|
||||
|
@ -383,6 +384,21 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskIconChanged(String pkg, UserHandle user) {
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
TaskView tv = getTaskViewAt(i);
|
||||
Task task = tv.getTask();
|
||||
if (task != null && task.key != null && pkg.equals(task.key.getPackageName())
|
||||
&& task.key.userId == user.getIdentifier()) {
|
||||
task.icon = null;
|
||||
if (tv.getIconView().getDrawable() != null) {
|
||||
tv.onTaskListVisibilityChanged(true /* visible */);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the thumbnail of the task.
|
||||
* @param refreshNow Refresh immediately if it's true.
|
||||
|
|
|
@ -28,7 +28,9 @@ import android.content.Context;
|
|||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.icons.IconProvider;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
@ -50,7 +52,7 @@ public class RecentsModel extends TaskStackChangeListener {
|
|||
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
|
||||
new MainThreadInitializedObject<>(RecentsModel::new);
|
||||
|
||||
private final List<TaskThumbnailChangeListener> mThumbnailChangeListeners = new ArrayList<>();
|
||||
private final List<TaskVisualsChangeListener> mThumbnailChangeListeners = new ArrayList<>();
|
||||
private final Context mContext;
|
||||
|
||||
private final RecentTasksList mTaskList;
|
||||
|
@ -65,7 +67,10 @@ public class RecentsModel extends TaskStackChangeListener {
|
|||
new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
|
||||
mIconCache = new TaskIconCache(context, looper);
|
||||
mThumbnailCache = new TaskThumbnailCache(context, looper);
|
||||
|
||||
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
|
||||
IconProvider.registerIconChangeListener(context,
|
||||
this::onPackageIconChanged, MAIN_EXECUTOR.getHandler());
|
||||
}
|
||||
|
||||
public TaskIconCache getIconCache() {
|
||||
|
@ -178,16 +183,40 @@ public class RecentsModel extends TaskStackChangeListener {
|
|||
}
|
||||
}
|
||||
|
||||
public void addThumbnailChangeListener(TaskThumbnailChangeListener listener) {
|
||||
private void onPackageIconChanged(String pkg, UserHandle user) {
|
||||
mIconCache.invalidateCacheEntries(pkg, user);
|
||||
for (int i = mThumbnailChangeListeners.size() - 1; i >= 0; i--) {
|
||||
mThumbnailChangeListeners.get(i).onTaskIconChanged(pkg, user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for visuals changes
|
||||
*/
|
||||
public void addThumbnailChangeListener(TaskVisualsChangeListener listener) {
|
||||
mThumbnailChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeThumbnailChangeListener(TaskThumbnailChangeListener listener) {
|
||||
/**
|
||||
* Removes a previously added listener
|
||||
*/
|
||||
public void removeThumbnailChangeListener(TaskVisualsChangeListener listener) {
|
||||
mThumbnailChangeListeners.remove(listener);
|
||||
}
|
||||
|
||||
public interface TaskThumbnailChangeListener {
|
||||
/**
|
||||
* Listener for receiving various task properties changes
|
||||
*/
|
||||
public interface TaskVisualsChangeListener {
|
||||
|
||||
/**
|
||||
* Called whn the task thumbnail changes
|
||||
*/
|
||||
Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData);
|
||||
|
||||
/**
|
||||
* Called when the icon for a task changes
|
||||
*/
|
||||
void onTaskIconChanged(String pkg, UserHandle user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.FastBitmapDrawable.newIcon;
|
||||
import static com.android.launcher3.uioverrides.QuickstepLauncher.GO_LOW_RAM_RECENTS_ENABLED;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
|
||||
|
@ -37,14 +38,14 @@ import androidx.annotation.WorkerThread;
|
|||
import com.android.launcher3.FastBitmapDrawable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.IconProvider;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.icons.cache.HandlerRunnable;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.quickstep.util.TaskKeyLruCache;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.Task.TaskKey;
|
||||
import com.android.systemui.shared.recents.model.TaskKeyLruCache;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.PackageManagerWrapper;
|
||||
|
||||
|
@ -61,6 +62,7 @@ public class TaskIconCache {
|
|||
private final Context mContext;
|
||||
private final TaskKeyLruCache<TaskCacheEntry> mIconCache;
|
||||
private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
|
||||
private final IconProvider mIconProvider;
|
||||
|
||||
public TaskIconCache(Context context, Looper backgroundLooper) {
|
||||
mContext = context;
|
||||
|
@ -70,6 +72,7 @@ public class TaskIconCache {
|
|||
Resources res = context.getResources();
|
||||
int cacheSize = res.getInteger(R.integer.recentsIconCacheSize);
|
||||
mIconCache = new TaskKeyLruCache<>(cacheSize);
|
||||
mIconProvider = new IconProvider(context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,6 +118,12 @@ public class TaskIconCache {
|
|||
mIconCache.remove(taskKey);
|
||||
}
|
||||
|
||||
void invalidateCacheEntries(String pkg, UserHandle handle) {
|
||||
Utilities.postAsyncCallback(mBackgroundHandler,
|
||||
() -> mIconCache.removeAll(key ->
|
||||
pkg.equals(key.getPackageName()) && handle.getIdentifier() == key.userId));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private TaskCacheEntry getCacheEntry(Task task) {
|
||||
TaskCacheEntry entry = mIconCache.getAndInvalidateIfModified(task.key);
|
||||
|
@ -143,12 +152,11 @@ public class TaskIconCache {
|
|||
key.getComponent(), key.userId);
|
||||
if (activityInfo != null) {
|
||||
BitmapInfo bitmapInfo = getBitmapInfo(
|
||||
activityInfo.loadUnbadgedIcon(mContext.getPackageManager()),
|
||||
mIconProvider.getIcon(activityInfo, UserHandle.of(key.userId)),
|
||||
key.userId,
|
||||
desc.getPrimaryColor(),
|
||||
activityInfo.applicationInfo.isInstantApp());
|
||||
entry.icon = DrawableFactory.INSTANCE.get(mContext).newIcon(
|
||||
mContext, bitmapInfo, activityInfo);
|
||||
entry.icon = newIcon(mContext, bitmapInfo);
|
||||
} else {
|
||||
entry.icon = getDefaultIcon(key.userId);
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ import com.android.launcher3.R;
|
|||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.icons.cache.HandlerRunnable;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.quickstep.util.TaskKeyLruCache;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.model.Task.TaskKey;
|
||||
import com.android.systemui.shared.recents.model.TaskKeyLruCache;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
|
@ -41,7 +41,7 @@ public class TaskThumbnailCache {
|
|||
private final Handler mBackgroundHandler;
|
||||
|
||||
private final int mCacheSize;
|
||||
private final ThumbnailCache mCache;
|
||||
private final TaskKeyLruCache<ThumbnailData> mCache;
|
||||
private final HighResLoadingState mHighResLoadingState;
|
||||
|
||||
public static class HighResLoadingState {
|
||||
|
@ -100,7 +100,7 @@ public class TaskThumbnailCache {
|
|||
|
||||
Resources res = context.getResources();
|
||||
mCacheSize = res.getInteger(R.integer.recentsThumbnailCacheSize);
|
||||
mCache = new ThumbnailCache(mCacheSize);
|
||||
mCache = new TaskKeyLruCache<>(mCacheSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,21 +223,4 @@ public class TaskThumbnailCache {
|
|||
this.reducedResolution = reducedResolution;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ThumbnailCache extends TaskKeyLruCache<ThumbnailData> {
|
||||
|
||||
public ThumbnailCache(int cacheSize) {
|
||||
super(cacheSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cache entry if it is already present in the cache
|
||||
*/
|
||||
public void updateIfAlreadyInCache(int taskId, ThumbnailData thumbnailData) {
|
||||
ThumbnailData oldData = getCacheEntry(taskId);
|
||||
if (oldData != null) {
|
||||
putCacheEntry(taskId, thumbnailData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (C) 2019 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.quickstep.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.shared.recents.model.Task.TaskKey;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A simple LRU cache for task key entries
|
||||
* @param <V> The type of the value
|
||||
*/
|
||||
public class TaskKeyLruCache<V> {
|
||||
|
||||
private final MyLinkedHashMap<V> mMap;
|
||||
|
||||
public TaskKeyLruCache(int maxSize) {
|
||||
mMap = new MyLinkedHashMap<>(maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all entries from the cache
|
||||
*/
|
||||
public synchronized void evictAll() {
|
||||
mMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a particular entry from the cache
|
||||
*/
|
||||
public synchronized void remove(TaskKey key) {
|
||||
mMap.remove(key.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all entries matching keyCheck
|
||||
*/
|
||||
public synchronized void removeAll(Predicate<TaskKey> keyCheck) {
|
||||
mMap.entrySet().removeIf(e -> keyCheck.test(e.getValue().mKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry if it is still valid
|
||||
*/
|
||||
public synchronized V getAndInvalidateIfModified(TaskKey key) {
|
||||
Entry<V> entry = mMap.get(key.id);
|
||||
|
||||
if (entry != null && entry.mKey.windowingMode == key.windowingMode
|
||||
&& entry.mKey.lastActiveTime == key.lastActiveTime) {
|
||||
return entry.mValue;
|
||||
} else {
|
||||
remove(key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the cache, optionally evicting the last accessed entry
|
||||
*/
|
||||
public final synchronized void put(TaskKey key, V value) {
|
||||
if (key != null && value != null) {
|
||||
mMap.put(key.id, new Entry<>(key, value));
|
||||
} else {
|
||||
Log.e("TaskKeyCache", "Unexpected null key or value: " + key + ", " + value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cache entry if it is already present in the cache
|
||||
*/
|
||||
public synchronized void updateIfAlreadyInCache(int taskId, V data) {
|
||||
Entry<V> entry = mMap.get(taskId);
|
||||
if (entry != null) {
|
||||
entry.mValue = data;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Entry<V> {
|
||||
|
||||
final TaskKey mKey;
|
||||
V mValue;
|
||||
|
||||
Entry(TaskKey key, V value) {
|
||||
mKey = key;
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mKey.id;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyLinkedHashMap<V> extends LinkedHashMap<Integer, Entry<V>> {
|
||||
|
||||
private final int mMaxSize;
|
||||
|
||||
MyLinkedHashMap(int maxSize) {
|
||||
super(0, 0.75f, true /* accessOrder */);
|
||||
mMaxSize = maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Entry<Integer, TaskKeyLruCache.Entry<V>> eldest) {
|
||||
return size() > mMaxSize;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<resources>
|
||||
<!-- Miscellaneous -->
|
||||
<!-- Miscellaneous -->
|
||||
<bool name="config_largeHeap">false</bool>
|
||||
<bool name="is_tablet">false</bool>
|
||||
<bool name="is_large_tablet">false</bool>
|
||||
|
@ -21,10 +21,10 @@
|
|||
<!-- String representing the fragment class for settings activity.-->
|
||||
<string name="settings_fragment_name" translatable="false">com.android.launcher3.settings.SettingsActivity$LauncherSettingsFragment</string>
|
||||
|
||||
<!-- DragController -->
|
||||
<!-- DragController -->
|
||||
<item type="id" name="drag_event_parity" />
|
||||
|
||||
<!-- AllApps & Launcher transitions -->
|
||||
<!-- AllApps & Launcher transitions -->
|
||||
<!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
|
||||
<integer name="config_workspaceSpringLoadShrinkPercentage">90</integer>
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
<!-- View tag key used to store SpringAnimation data. -->
|
||||
<item type="id" name="spring_animation_tag" />
|
||||
|
||||
<!-- Workspace -->
|
||||
<!-- Workspace -->
|
||||
<!-- The duration (in ms) of the fade animation on the object outlines, used when
|
||||
we are dragging objects around on the home screen. -->
|
||||
<integer name="config_dragOutlineFadeTime">900</integer>
|
||||
|
@ -57,13 +57,11 @@
|
|||
<!-- The duration of the caret animation -->
|
||||
<integer name="config_caretAnimationDuration">200</integer>
|
||||
|
||||
<!-- Hotseat -->
|
||||
<!-- Hotseat -->
|
||||
<bool name="hotseat_transpose_layout_with_orientation">true</bool>
|
||||
|
||||
<!-- Various classes overriden by projects/build flavors. -->
|
||||
<string name="app_filter_class" translatable="false"></string>
|
||||
<string name="icon_provider_class" translatable="false"></string>
|
||||
<string name="drawable_factory_class" translatable="false"></string>
|
||||
<string name="user_event_dispatcher_class" translatable="false"></string>
|
||||
<string name="stats_log_manager_class" translatable="false"></string>
|
||||
<string name="app_transition_manager_class" translatable="false"></string>
|
||||
|
@ -73,12 +71,6 @@
|
|||
<string name="test_information_handler_class" translatable="false"></string>
|
||||
<string name="launcher_activity_logic_class" translatable="false"></string>
|
||||
|
||||
<!-- Package name of the default wallpaper picker. -->
|
||||
<string name="wallpaper_picker_package" translatable="false"></string>
|
||||
|
||||
<!-- Whitelisted package to retrieve packagename for badge. Can be empty. -->
|
||||
<string name="shortcutinfo_badgepkg_whitelist" translatable="false"></string>
|
||||
|
||||
<!-- View ID to use for QSB widget -->
|
||||
<item type="id" name="qsb_widget" />
|
||||
|
||||
|
@ -96,7 +88,12 @@
|
|||
<integer name="config_popupArrowOpenCloseDuration">40</integer>
|
||||
<integer name="config_removeNotificationViewDuration">300</integer>
|
||||
|
||||
<!-- Accessibility actions -->
|
||||
<!-- Default packages -->
|
||||
<string name="wallpaper_picker_package" translatable="false"></string>
|
||||
<string name="calendar_component_name" translatable="false"></string>
|
||||
<string name="clock_component_name" translatable="false"></string>
|
||||
|
||||
<!-- Accessibility actions -->
|
||||
<item type="id" name="action_remove" />
|
||||
<item type="id" name="action_uninstall" />
|
||||
<item type="id" name="action_reconfigure" />
|
||||
|
@ -111,10 +108,10 @@
|
|||
<item type="id" name="action_dismiss_notification" />
|
||||
<item type="id" name="action_remote_action_shortcut" />
|
||||
|
||||
<!-- QSB IDs. DO not change -->
|
||||
<!-- QSB IDs. DO not change -->
|
||||
<item type="id" name="search_container_workspace" />
|
||||
<item type="id" name="search_container_all_apps" />
|
||||
|
||||
<!-- Recents -->
|
||||
<!-- Recents -->
|
||||
<item type="id" name="overview_panel"/>
|
||||
</resources>
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.FastBitmapDrawable.newIcon;
|
||||
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
|
||||
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
||||
|
||||
import android.animation.Animator;
|
||||
|
@ -45,7 +47,6 @@ import com.android.launcher3.Launcher.OnResumeCallback;
|
|||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.dot.DotInfo;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.graphics.IconPalette;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.graphics.PreloadIconDrawable;
|
||||
|
@ -287,8 +288,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
|||
}
|
||||
|
||||
private void applyIconAndLabel(ItemInfoWithIcon info) {
|
||||
FastBitmapDrawable iconDrawable = DrawableFactory.INSTANCE.get(getContext())
|
||||
.newIcon(getContext(), info);
|
||||
FastBitmapDrawable iconDrawable = newIcon(getContext(), info);
|
||||
mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f);
|
||||
|
||||
setIcon(iconDrawable);
|
||||
|
@ -567,8 +567,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
|||
preloadDrawable = (PreloadIconDrawable) mIcon;
|
||||
preloadDrawable.setLevel(progressLevel);
|
||||
} else {
|
||||
preloadDrawable = DrawableFactory.INSTANCE.get(getContext())
|
||||
.newPendingIcon(getContext(), info);
|
||||
preloadDrawable = newPendingIcon(getContext(), info);
|
||||
preloadDrawable.setLevel(progressLevel);
|
||||
setIcon(preloadDrawable);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import static com.android.launcher3.anim.Interpolators.ACCEL;
|
|||
import static com.android.launcher3.anim.Interpolators.DEACCEL;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
|
@ -35,6 +36,7 @@ import android.graphics.drawable.Drawable;
|
|||
import android.util.Property;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.launcher3.graphics.PlaceHolderIconDrawable;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
|
||||
public class FastBitmapDrawable extends Drawable {
|
||||
|
@ -361,7 +363,7 @@ public class FastBitmapDrawable extends Drawable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Drawable newDrawable() {
|
||||
public FastBitmapDrawable newDrawable() {
|
||||
return new FastBitmapDrawable(mBitmap, mIconColor, mIsDisabled);
|
||||
}
|
||||
|
||||
|
@ -370,4 +372,37 @@ public class FastBitmapDrawable extends Drawable {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to be implemented by custom {@link BitmapInfo} to handle drawable construction
|
||||
*/
|
||||
public interface Factory {
|
||||
|
||||
/**
|
||||
* Called to create a new drawable
|
||||
*/
|
||||
FastBitmapDrawable newDrawable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FastBitmapDrawable with the icon.
|
||||
*/
|
||||
public static FastBitmapDrawable newIcon(Context context, ItemInfoWithIcon info) {
|
||||
FastBitmapDrawable drawable = newIcon(context, info.bitmap);
|
||||
drawable.setIsDisabled(info.isDisabled());
|
||||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a drawable for the provided BitmapInfo
|
||||
*/
|
||||
public static FastBitmapDrawable newIcon(Context context, BitmapInfo info) {
|
||||
if (info instanceof Factory) {
|
||||
return ((Factory) info).newDrawable();
|
||||
} else if (info.isLowRes()) {
|
||||
return new PlaceHolderIconDrawable(info, context);
|
||||
} else {
|
||||
return new FastBitmapDrawable(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
||||
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
|
||||
public class IconProvider implements ResourceBasedOverride {
|
||||
|
||||
public static MainThreadInitializedObject<IconProvider> INSTANCE =
|
||||
forOverride(IconProvider.class, R.string.icon_provider_class);
|
||||
|
||||
public IconProvider() { }
|
||||
|
||||
public String getSystemStateForPackage(String systemState, String packageName) {
|
||||
return systemState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flattenDrawable true if the caller does not care about the specification of the
|
||||
* original icon as long as the flattened version looks the same.
|
||||
*/
|
||||
public Drawable getIcon(LauncherActivityInfo info, int iconDpi, boolean flattenDrawable) {
|
||||
return info.getIcon(iconDpi);
|
||||
}
|
||||
}
|
|
@ -30,12 +30,14 @@ import android.util.Log;
|
|||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.icons.IconProvider;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.notification.NotificationListener;
|
||||
import com.android.launcher3.pm.InstallSessionTracker;
|
||||
import com.android.launcher3.pm.PackageInstallerCompat;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.util.SecureSettingsObserver;
|
||||
import com.android.launcher3.util.SimpleBroadcastReceiver;
|
||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||
|
@ -57,6 +59,7 @@ public class LauncherAppState {
|
|||
|
||||
private final InstallSessionTracker mInstallSessionTracker;
|
||||
private final SimpleBroadcastReceiver mModelChangeReceiver;
|
||||
private final SafeCloseable mCalendarChangeTracker;
|
||||
|
||||
public static LauncherAppState getInstance(final Context context) {
|
||||
return INSTANCE.get(context);
|
||||
|
@ -92,6 +95,10 @@ public class LauncherAppState {
|
|||
if (FeatureFlags.IS_DOGFOOD_BUILD) {
|
||||
mModelChangeReceiver.register(mContext, ACTION_FORCE_ROLOAD);
|
||||
}
|
||||
|
||||
mCalendarChangeTracker = IconProvider.registerIconChangeListener(mContext,
|
||||
mModel::onAppIconChanged, MODEL_EXECUTOR.getHandler());
|
||||
|
||||
// TODO: remove listener on terminate
|
||||
FeatureFlags.APP_SEARCH_IMPROVEMENTS.addChangeListener(context, mModel::forceReload);
|
||||
CustomWidgetManager.INSTANCE.get(mContext)
|
||||
|
@ -143,6 +150,7 @@ public class LauncherAppState {
|
|||
mContext.unregisterReceiver(mModelChangeReceiver);
|
||||
mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel);
|
||||
mInstallSessionTracker.unregister();
|
||||
mCalendarChangeTracker.close();
|
||||
CustomWidgetManager.INSTANCE.get(mContext).setWidgetRefreshCallback(null);
|
||||
|
||||
if (mNotificationDotsObserver != null) {
|
||||
|
|
|
@ -21,6 +21,7 @@ import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
|
|||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageInstaller;
|
||||
|
@ -31,6 +32,7 @@ import android.util.Log;
|
|||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
|
@ -53,7 +55,6 @@ import com.android.launcher3.model.UserLockStateChangedTask;
|
|||
import com.android.launcher3.pm.InstallSessionTracker;
|
||||
import com.android.launcher3.pm.PackageInstallInfo;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.IntSparseArrayMap;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
|
@ -210,9 +211,21 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
|
|||
enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, shortcuts, user, true));
|
||||
}
|
||||
|
||||
public void updatePinnedShortcuts(String packageName, List<ShortcutInfo> shortcuts,
|
||||
UserHandle user) {
|
||||
enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, shortcuts, user, false));
|
||||
/**
|
||||
* Called when the icon for an app changes, outside of package event
|
||||
*/
|
||||
@WorkerThread
|
||||
public void onAppIconChanged(String packageName, UserHandle user) {
|
||||
// Update the icon for the calendar package
|
||||
Context context = mApp.getContext();
|
||||
onPackageChanged(packageName, user);
|
||||
|
||||
List<ShortcutInfo> pinnedShortcuts = DeepShortcutManager.getInstance(context)
|
||||
.queryForPinnedShortcuts(packageName, user);
|
||||
if (!pinnedShortcuts.isEmpty()) {
|
||||
enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, pinnedShortcuts, user,
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
||||
public void onBroadcastIntent(Intent intent) {
|
||||
|
|
|
@ -63,6 +63,7 @@ import android.view.animation.Interpolator;
|
|||
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
|
||||
import com.android.launcher3.graphics.RotationMode;
|
||||
import com.android.launcher3.graphics.TintedDrawableSpan;
|
||||
import com.android.launcher3.icons.IconProvider;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
|
@ -518,19 +519,20 @@ public final class Utilities {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the full drawable for {@param info}.
|
||||
* Returns the full drawable for info without any flattening or pre-processing.
|
||||
*
|
||||
* @param outObj this is set to the internal data associated with {@param info},
|
||||
* eg {@link LauncherActivityInfo} or {@link ShortcutInfo}.
|
||||
*/
|
||||
public static Drawable getFullDrawable(Launcher launcher, ItemInfo info, int width, int height,
|
||||
boolean flattenDrawable, Object[] outObj) {
|
||||
Object[] outObj) {
|
||||
LauncherAppState appState = LauncherAppState.getInstance(launcher);
|
||||
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
|
||||
LauncherActivityInfo activityInfo = launcher.getSystemService(LauncherApps.class)
|
||||
.resolveActivity(info.getIntent(), info.user);
|
||||
outObj[0] = activityInfo;
|
||||
return (activityInfo != null) ? appState.getIconCache()
|
||||
.getFullResIcon(activityInfo, flattenDrawable) : null;
|
||||
return activityInfo == null ? null : new IconProvider(launcher).getIconForUI(
|
||||
activityInfo, launcher.getDeviceProfile().inv.fillResIconDpi);
|
||||
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
if (info instanceof PendingAddShortcutInfo) {
|
||||
ShortcutConfigActivityInfo activityInfo =
|
||||
|
|
|
@ -23,16 +23,19 @@ import android.graphics.PorterDuff;
|
|||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
|
@ -78,6 +81,9 @@ public class WidgetPreviewLoader {
|
|||
private final UserManagerCompat mUserManager;
|
||||
private final CacheDb mDb;
|
||||
|
||||
private final UserHandle mMyUser = Process.myUserHandle();
|
||||
private final ArrayMap<UserHandle, Bitmap> mUserBadges = new ArrayMap<>();
|
||||
|
||||
public WidgetPreviewLoader(Context context, IconCache iconCache) {
|
||||
mContext = context;
|
||||
mIconCache = iconCache;
|
||||
|
@ -85,6 +91,51 @@ public class WidgetPreviewLoader {
|
|||
mDb = new CacheDb(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a drawable that can be used as a badge for the user or null.
|
||||
*/
|
||||
@UiThread
|
||||
public Drawable getBadgeForUser(UserHandle user, int badgeSize) {
|
||||
if (mMyUser.equals(user)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap badgeBitmap = getUserBadge(user, badgeSize);
|
||||
FastBitmapDrawable d = new FastBitmapDrawable(badgeBitmap);
|
||||
d.setFilterBitmap(true);
|
||||
d.setBounds(0, 0, badgeBitmap.getWidth(), badgeBitmap.getHeight());
|
||||
return d;
|
||||
}
|
||||
|
||||
private Bitmap getUserBadge(UserHandle user, int badgeSize) {
|
||||
synchronized (mUserBadges) {
|
||||
Bitmap badgeBitmap = mUserBadges.get(user);
|
||||
if (badgeBitmap != null) {
|
||||
return badgeBitmap;
|
||||
}
|
||||
|
||||
final Resources res = mContext.getResources();
|
||||
badgeBitmap = Bitmap.createBitmap(badgeSize, badgeSize, Bitmap.Config.ARGB_8888);
|
||||
|
||||
Drawable drawable = mContext.getPackageManager().getUserBadgedDrawableForDensity(
|
||||
new BitmapDrawable(res, badgeBitmap), user,
|
||||
new Rect(0, 0, badgeSize, badgeSize),
|
||||
0);
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
badgeBitmap = ((BitmapDrawable) drawable).getBitmap();
|
||||
} else {
|
||||
badgeBitmap.eraseColor(Color.TRANSPARENT);
|
||||
Canvas c = new Canvas(badgeBitmap);
|
||||
drawable.setBounds(0, 0, badgeSize, badgeSize);
|
||||
drawable.draw(c);
|
||||
c.setBitmap(null);
|
||||
}
|
||||
|
||||
mUserBadges.put(user, badgeBitmap);
|
||||
return badgeBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the widget preview on {@link AsyncTask#THREAD_POOL_EXECUTOR}. Must be
|
||||
* called on UI thread
|
||||
|
@ -106,8 +157,8 @@ public class WidgetPreviewLoader {
|
|||
|
||||
public void refresh() {
|
||||
mDb.clear();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The DB holds the generated previews for various components. Previews can also have different
|
||||
* sizes (landscape vs portrait).
|
||||
|
|
|
@ -216,8 +216,7 @@ public class DragView extends View implements LauncherStateManager.StateListener
|
|||
Object[] outObj = new Object[1];
|
||||
int w = mBitmap.getWidth();
|
||||
int h = mBitmap.getHeight();
|
||||
Drawable dr = Utilities.getFullDrawable(mLauncher, info, w, h,
|
||||
false /* flattenDrawable */, outObj);
|
||||
Drawable dr = Utilities.getFullDrawable(mLauncher, info, w, h, outObj);
|
||||
|
||||
if (dr instanceof AdaptiveIconDrawable) {
|
||||
int blurMargin = (int) mLauncher.getResources()
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
|
||||
package com.android.launcher3.folder;
|
||||
|
||||
import static com.android.launcher3.FastBitmapDrawable.newIcon;
|
||||
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX;
|
||||
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX;
|
||||
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
|
||||
import static com.android.launcher3.folder.FolderIcon.DROP_IN_ANIMATION_DURATION;
|
||||
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
|
@ -38,7 +40,6 @@ import androidx.annotation.NonNull;
|
|||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.graphics.PreloadIconDrawable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -66,7 +67,6 @@ public class PreviewItemManager {
|
|||
|
||||
private final Context mContext;
|
||||
private final FolderIcon mIcon;
|
||||
private final DrawableFactory mDrawableFactory;
|
||||
private final int mIconSize;
|
||||
|
||||
// These variables are all associated with the drawing of the preview; they are stored
|
||||
|
@ -94,7 +94,6 @@ public class PreviewItemManager {
|
|||
public PreviewItemManager(FolderIcon icon) {
|
||||
mContext = icon.getContext();
|
||||
mIcon = icon;
|
||||
mDrawableFactory = DrawableFactory.INSTANCE.get(mContext);
|
||||
mIconSize = Launcher.getLauncher(mContext).getDeviceProfile().folderChildIconSizePx;
|
||||
}
|
||||
|
||||
|
@ -395,11 +394,11 @@ public class PreviewItemManager {
|
|||
|
||||
private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) {
|
||||
if (item.hasPromiseIconUi()) {
|
||||
PreloadIconDrawable drawable = mDrawableFactory.newPendingIcon(mContext, item);
|
||||
PreloadIconDrawable drawable = newPendingIcon(mContext, item);
|
||||
drawable.setLevel(item.getInstallProgress());
|
||||
p.drawable = drawable;
|
||||
} else {
|
||||
p.drawable = mDrawableFactory.newIcon(mContext, item);
|
||||
p.drawable = newIcon(mContext, item);
|
||||
}
|
||||
p.drawable.setBounds(0, 0, mIconSize, mIconSize);
|
||||
p.item = item;
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* 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.graphics;
|
||||
|
||||
import static com.android.launcher3.graphics.IconShape.getShapePath;
|
||||
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.FastBitmapDrawable;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
|
||||
/**
|
||||
* Factory for creating new drawables.
|
||||
*/
|
||||
public class DrawableFactory implements ResourceBasedOverride {
|
||||
|
||||
public static final MainThreadInitializedObject<DrawableFactory> INSTANCE =
|
||||
forOverride(DrawableFactory.class, R.string.drawable_factory_class);
|
||||
|
||||
protected final UserHandle mMyUser = Process.myUserHandle();
|
||||
protected final ArrayMap<UserHandle, Bitmap> mUserBadges = new ArrayMap<>();
|
||||
|
||||
/**
|
||||
* Returns a FastBitmapDrawable with the icon.
|
||||
*/
|
||||
public FastBitmapDrawable newIcon(Context context, ItemInfoWithIcon info) {
|
||||
FastBitmapDrawable drawable = info.usingLowResIcon()
|
||||
? new PlaceHolderIconDrawable(info.bitmap, getShapePath(), context)
|
||||
: new FastBitmapDrawable(info.bitmap);
|
||||
drawable.setIsDisabled(info.isDisabled());
|
||||
return drawable;
|
||||
}
|
||||
|
||||
public FastBitmapDrawable newIcon(Context context, BitmapInfo info, ActivityInfo target) {
|
||||
return info.isLowRes()
|
||||
? new PlaceHolderIconDrawable(info, getShapePath(), context)
|
||||
: new FastBitmapDrawable(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FastBitmapDrawable with the icon.
|
||||
*/
|
||||
public PreloadIconDrawable newPendingIcon(Context context, ItemInfoWithIcon info) {
|
||||
return new PreloadIconDrawable(info, getShapePath(), context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a drawable that can be used as a badge for the user or null.
|
||||
*/
|
||||
@UiThread
|
||||
public Drawable getBadgeForUser(UserHandle user, Context context, int badgeSize) {
|
||||
if (mMyUser.equals(user)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap badgeBitmap = getUserBadge(user, context, badgeSize);
|
||||
FastBitmapDrawable d = new FastBitmapDrawable(badgeBitmap);
|
||||
d.setFilterBitmap(true);
|
||||
d.setBounds(0, 0, badgeBitmap.getWidth(), badgeBitmap.getHeight());
|
||||
return d;
|
||||
}
|
||||
|
||||
protected synchronized Bitmap getUserBadge(UserHandle user, Context context, int badgeSize) {
|
||||
Bitmap badgeBitmap = mUserBadges.get(user);
|
||||
if (badgeBitmap != null) {
|
||||
return badgeBitmap;
|
||||
}
|
||||
|
||||
final Resources res = context.getApplicationContext().getResources();
|
||||
badgeBitmap = Bitmap.createBitmap(badgeSize, badgeSize, Bitmap.Config.ARGB_8888);
|
||||
|
||||
Drawable drawable = context.getPackageManager().getUserBadgedDrawableForDensity(
|
||||
new BitmapDrawable(res, badgeBitmap), user, new Rect(0, 0, badgeSize, badgeSize),
|
||||
0);
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
badgeBitmap = ((BitmapDrawable) drawable).getBitmap();
|
||||
} else {
|
||||
badgeBitmap.eraseColor(Color.TRANSPARENT);
|
||||
Canvas c = new Canvas(badgeBitmap);
|
||||
drawable.setBounds(0, 0, badgeSize, badgeSize);
|
||||
drawable.draw(c);
|
||||
c.setBitmap(null);
|
||||
}
|
||||
|
||||
mUserBadges.put(user, badgeBitmap);
|
||||
return badgeBitmap;
|
||||
}
|
||||
}
|
|
@ -17,8 +17,9 @@ package com.android.launcher3.graphics;
|
|||
|
||||
import static androidx.core.graphics.ColorUtils.compositeColors;
|
||||
|
||||
import static com.android.launcher3.graphics.IconShape.getShapePath;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
|
@ -36,16 +37,12 @@ public class PlaceHolderIconDrawable extends FastBitmapDrawable {
|
|||
// Path in [0, 100] bounds.
|
||||
private final Path mProgressPath;
|
||||
|
||||
public PlaceHolderIconDrawable(BitmapInfo info, Path progressPath, Context context) {
|
||||
this(info.icon, info.color, progressPath, context);
|
||||
}
|
||||
public PlaceHolderIconDrawable(BitmapInfo info, Context context) {
|
||||
super(info);
|
||||
|
||||
protected PlaceHolderIconDrawable(Bitmap b, int iconColor, Path progressPath, Context context) {
|
||||
super(b, iconColor);
|
||||
|
||||
mProgressPath = progressPath;
|
||||
mProgressPath = getShapePath();
|
||||
mPaint.setColor(compositeColors(
|
||||
Themes.getAttrColor(context, R.attr.loadingIconColor), iconColor));
|
||||
Themes.getAttrColor(context, R.attr.loadingIconColor), info.color));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package com.android.launcher3.graphics;
|
||||
|
||||
import static com.android.launcher3.graphics.IconShape.DEFAULT_PATH_SIZE;
|
||||
import static com.android.launcher3.graphics.IconShape.getShapePath;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
|
@ -101,13 +102,10 @@ public class PreloadIconDrawable extends FastBitmapDrawable {
|
|||
|
||||
private ObjectAnimator mCurrentAnim;
|
||||
|
||||
/**
|
||||
* @param progressPath fixed path in the bounds [0, 0, 100, 100] representing a progress bar.
|
||||
*/
|
||||
public PreloadIconDrawable(ItemInfoWithIcon info, Path progressPath, Context context) {
|
||||
public PreloadIconDrawable(ItemInfoWithIcon info, Context context) {
|
||||
super(info.bitmap);
|
||||
mItem = info;
|
||||
mProgressPath = progressPath;
|
||||
mProgressPath = getShapePath();
|
||||
mScaledTrackPath = new Path();
|
||||
mScaledProgressPath = new Path();
|
||||
|
||||
|
@ -289,4 +287,11 @@ public class PreloadIconDrawable extends FastBitmapDrawable {
|
|||
}
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FastBitmapDrawable with the icon.
|
||||
*/
|
||||
public static PreloadIconDrawable newPendingIcon(Context context, ItemInfoWithIcon info) {
|
||||
return new PreloadIconDrawable(info, context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* Copyright (C) 2019 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.icons;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.FastBitmapDrawable;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Wrapper over {@link AdaptiveIconDrawable} to intercept icon flattening logic for dynamic
|
||||
* clock icons
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public class ClockDrawableWrapper extends AdaptiveIconDrawable implements BitmapInfo.Extender {
|
||||
|
||||
private static final String TAG = "ClockDrawableWrapper";
|
||||
|
||||
private static final boolean DISABLE_SECONDS = true;
|
||||
|
||||
// Time after which the clock icon should check for an update. The actual invalidate
|
||||
// will only happen in case of any change.
|
||||
public static final long TICK_MS = DISABLE_SECONDS ? TimeUnit.MINUTES.toMillis(1) : 200L;
|
||||
|
||||
private static final String LAUNCHER_PACKAGE = "com.android.launcher3";
|
||||
private static final String ROUND_ICON_METADATA_KEY = LAUNCHER_PACKAGE
|
||||
+ ".LEVEL_PER_TICK_ICON_ROUND";
|
||||
private static final String HOUR_INDEX_METADATA_KEY = LAUNCHER_PACKAGE + ".HOUR_LAYER_INDEX";
|
||||
private static final String MINUTE_INDEX_METADATA_KEY = LAUNCHER_PACKAGE
|
||||
+ ".MINUTE_LAYER_INDEX";
|
||||
private static final String SECOND_INDEX_METADATA_KEY = LAUNCHER_PACKAGE
|
||||
+ ".SECOND_LAYER_INDEX";
|
||||
private static final String DEFAULT_HOUR_METADATA_KEY = LAUNCHER_PACKAGE
|
||||
+ ".DEFAULT_HOUR";
|
||||
private static final String DEFAULT_MINUTE_METADATA_KEY = LAUNCHER_PACKAGE
|
||||
+ ".DEFAULT_MINUTE";
|
||||
private static final String DEFAULT_SECOND_METADATA_KEY = LAUNCHER_PACKAGE
|
||||
+ ".DEFAULT_SECOND";
|
||||
|
||||
/* Number of levels to jump per second for the second hand */
|
||||
private static final int LEVELS_PER_SECOND = 10;
|
||||
|
||||
public static final int INVALID_VALUE = -1;
|
||||
|
||||
private final AnimationInfo mAnimationInfo = new AnimationInfo();
|
||||
private int mTargetSdkVersion;
|
||||
|
||||
public ClockDrawableWrapper(AdaptiveIconDrawable base) {
|
||||
super(base.getBackground(), base.getForeground());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and returns the wrapper from the provided package, or returns null
|
||||
* if it is unable to load.
|
||||
*/
|
||||
public static ClockDrawableWrapper forPackage(Context context, String pkg, int iconDpi) {
|
||||
try {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
|
||||
final Bundle metadata = appInfo.metaData;
|
||||
if (metadata == null) {
|
||||
return null;
|
||||
}
|
||||
int drawableId = metadata.getInt(ROUND_ICON_METADATA_KEY, 0);
|
||||
if (drawableId == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Drawable drawable = pm.getResourcesForApplication(appInfo).getDrawableForDensity(
|
||||
drawableId, iconDpi).mutate();
|
||||
if (!(drawable instanceof AdaptiveIconDrawable)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClockDrawableWrapper wrapper =
|
||||
new ClockDrawableWrapper((AdaptiveIconDrawable) drawable);
|
||||
wrapper.mTargetSdkVersion = appInfo.targetSdkVersion;
|
||||
AnimationInfo info = wrapper.mAnimationInfo;
|
||||
|
||||
info.baseDrawableState = drawable.getConstantState();
|
||||
|
||||
info.hourLayerIndex = metadata.getInt(HOUR_INDEX_METADATA_KEY, INVALID_VALUE);
|
||||
info.minuteLayerIndex = metadata.getInt(MINUTE_INDEX_METADATA_KEY, INVALID_VALUE);
|
||||
info.secondLayerIndex = metadata.getInt(SECOND_INDEX_METADATA_KEY, INVALID_VALUE);
|
||||
|
||||
info.defaultHour = metadata.getInt(DEFAULT_HOUR_METADATA_KEY, 0);
|
||||
info.defaultMinute = metadata.getInt(DEFAULT_MINUTE_METADATA_KEY, 0);
|
||||
info.defaultSecond = metadata.getInt(DEFAULT_SECOND_METADATA_KEY, 0);
|
||||
|
||||
LayerDrawable foreground = (LayerDrawable) wrapper.getForeground();
|
||||
int layerCount = foreground.getNumberOfLayers();
|
||||
if (info.hourLayerIndex < 0 || info.hourLayerIndex >= layerCount) {
|
||||
info.hourLayerIndex = INVALID_VALUE;
|
||||
}
|
||||
if (info.minuteLayerIndex < 0 || info.minuteLayerIndex >= layerCount) {
|
||||
info.minuteLayerIndex = INVALID_VALUE;
|
||||
}
|
||||
if (info.secondLayerIndex < 0 || info.secondLayerIndex >= layerCount) {
|
||||
info.secondLayerIndex = INVALID_VALUE;
|
||||
} else if (DISABLE_SECONDS) {
|
||||
foreground.setDrawable(info.secondLayerIndex, null);
|
||||
info.secondLayerIndex = INVALID_VALUE;
|
||||
}
|
||||
return wrapper;
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Unable to load clock drawable info", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitmapInfo getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory) {
|
||||
iconFactory.disableColorExtraction();
|
||||
float [] scale = new float[1];
|
||||
AdaptiveIconDrawable background = new AdaptiveIconDrawable(
|
||||
getBackground().getConstantState().newDrawable(), null);
|
||||
BitmapInfo bitmapInfo = iconFactory.createBadgedIconBitmap(background,
|
||||
Process.myUserHandle(), mTargetSdkVersion, false, scale);
|
||||
|
||||
return new ClockBitmapInfo(bitmap, color, scale[0], mAnimationInfo, bitmapInfo.icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareToDrawOnUi() {
|
||||
mAnimationInfo.applyTime(Calendar.getInstance(), (LayerDrawable) getForeground());
|
||||
}
|
||||
|
||||
private static class AnimationInfo {
|
||||
|
||||
public ConstantState baseDrawableState;
|
||||
|
||||
public int hourLayerIndex;
|
||||
public int minuteLayerIndex;
|
||||
public int secondLayerIndex;
|
||||
public int defaultHour;
|
||||
public int defaultMinute;
|
||||
public int defaultSecond;
|
||||
|
||||
boolean applyTime(Calendar time, LayerDrawable foregroundDrawable) {
|
||||
time.setTimeInMillis(System.currentTimeMillis());
|
||||
|
||||
// We need to rotate by the difference from the default time if one is specified.
|
||||
int convertedHour = (time.get(Calendar.HOUR) + (12 - defaultHour)) % 12;
|
||||
int convertedMinute = (time.get(Calendar.MINUTE) + (60 - defaultMinute)) % 60;
|
||||
int convertedSecond = (time.get(Calendar.SECOND) + (60 - defaultSecond)) % 60;
|
||||
|
||||
boolean invalidate = false;
|
||||
if (hourLayerIndex != INVALID_VALUE) {
|
||||
final Drawable hour = foregroundDrawable.getDrawable(hourLayerIndex);
|
||||
if (hour.setLevel(convertedHour * 60 + time.get(Calendar.MINUTE))) {
|
||||
invalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (minuteLayerIndex != INVALID_VALUE) {
|
||||
final Drawable minute = foregroundDrawable.getDrawable(minuteLayerIndex);
|
||||
if (minute.setLevel(time.get(Calendar.HOUR) * 60 + convertedMinute)) {
|
||||
invalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (secondLayerIndex != INVALID_VALUE) {
|
||||
final Drawable second = foregroundDrawable.getDrawable(secondLayerIndex);
|
||||
if (second.setLevel(convertedSecond * LEVELS_PER_SECOND)) {
|
||||
invalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
return invalidate;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClockBitmapInfo extends BitmapInfo implements FastBitmapDrawable.Factory {
|
||||
|
||||
public final float scale;
|
||||
public final int offset;
|
||||
public final AnimationInfo animInfo;
|
||||
public final Bitmap mFlattenedBackground;
|
||||
|
||||
ClockBitmapInfo(Bitmap icon, int color, float scale, AnimationInfo animInfo,
|
||||
Bitmap background) {
|
||||
super(icon, color);
|
||||
this.scale = scale;
|
||||
this.animInfo = animInfo;
|
||||
this.offset = (int) Math.ceil(ShadowGenerator.BLUR_FACTOR * icon.getWidth());
|
||||
this.mFlattenedBackground = background;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastBitmapDrawable newDrawable() {
|
||||
return new ClockIconDrawable(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClockIconDrawable extends FastBitmapDrawable implements Runnable {
|
||||
|
||||
private final Calendar mTime = Calendar.getInstance();
|
||||
|
||||
private final ClockBitmapInfo mInfo;
|
||||
|
||||
private final AdaptiveIconDrawable mFullDrawable;
|
||||
private final LayerDrawable mForeground;
|
||||
|
||||
ClockIconDrawable(ClockBitmapInfo clockInfo) {
|
||||
super(clockInfo);
|
||||
|
||||
mInfo = clockInfo;
|
||||
|
||||
mFullDrawable = (AdaptiveIconDrawable) mInfo.animInfo.baseDrawableState.newDrawable();
|
||||
mForeground = (LayerDrawable) mFullDrawable.getForeground();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
mFullDrawable.setBounds(bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawInternal(Canvas canvas, Rect bounds) {
|
||||
if (mInfo == null) {
|
||||
super.drawInternal(canvas, bounds);
|
||||
return;
|
||||
}
|
||||
// draw the background that is already flattened to a bitmap
|
||||
canvas.drawBitmap(mInfo.mFlattenedBackground, null, bounds, mPaint);
|
||||
|
||||
// prepare and draw the foreground
|
||||
mInfo.animInfo.applyTime(mTime, mForeground);
|
||||
|
||||
canvas.scale(mInfo.scale, mInfo.scale,
|
||||
bounds.exactCenterX() + mInfo.offset, bounds.exactCenterY() + mInfo.offset);
|
||||
canvas.clipPath(mFullDrawable.getIconMask());
|
||||
mForeground.draw(canvas);
|
||||
|
||||
reschedule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateFilter() {
|
||||
super.updateFilter();
|
||||
mFullDrawable.setColorFilter(mPaint.getColorFilter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (mInfo.animInfo.applyTime(mTime, mForeground)) {
|
||||
invalidateSelf();
|
||||
} else {
|
||||
reschedule();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setVisible(boolean visible, boolean restart) {
|
||||
boolean result = super.setVisible(visible, restart);
|
||||
if (visible) {
|
||||
reschedule();
|
||||
} else {
|
||||
unscheduleSelf(this);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void reschedule() {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
unscheduleSelf(this);
|
||||
final long upTime = SystemClock.uptimeMillis();
|
||||
final long step = TICK_MS; /* tick every 200 ms */
|
||||
scheduleSelf(this, upTime - ((upTime % step)) + step);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstantState getConstantState() {
|
||||
return new ClockConstantState(mInfo, isDisabled());
|
||||
}
|
||||
|
||||
private static class ClockConstantState extends MyConstantState {
|
||||
|
||||
private final ClockBitmapInfo mInfo;
|
||||
|
||||
ClockConstantState(ClockBitmapInfo info, boolean isDisabled) {
|
||||
super(info.icon, info.color, isDisabled);
|
||||
mInfo = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastBitmapDrawable newDrawable() {
|
||||
ClockIconDrawable drawable = new ClockIconDrawable(mInfo);
|
||||
drawable.setIsDisabled(mIsDisabled);
|
||||
return drawable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,6 @@ import android.util.Log;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.AppInfo;
|
||||
import com.android.launcher3.IconProvider;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.LauncherFiles;
|
||||
|
@ -50,6 +49,7 @@ import com.android.launcher3.icons.cache.BaseIconCache;
|
|||
import com.android.launcher3.icons.cache.CachingLogic;
|
||||
import com.android.launcher3.icons.cache.HandlerRunnable;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.InstantAppResolver;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
|
@ -81,7 +81,7 @@ public class IconCache extends BaseIconCache {
|
|||
mLauncherApps = mContext.getSystemService(LauncherApps.class);
|
||||
mUserManager = UserManagerCompat.getInstance(mContext);
|
||||
mInstantAppResolver = InstantAppResolver.newInstance(mContext);
|
||||
mIconProvider = IconProvider.INSTANCE.get(context);
|
||||
mIconProvider = new IconProvider(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -230,11 +230,7 @@ public class IconCache extends BaseIconCache {
|
|||
}
|
||||
|
||||
public Drawable getFullResIcon(LauncherActivityInfo info) {
|
||||
return getFullResIcon(info, true);
|
||||
}
|
||||
|
||||
public Drawable getFullResIcon(LauncherActivityInfo info, boolean flattenDrawable) {
|
||||
return mIconProvider.getIcon(info, mIconDpi, flattenDrawable);
|
||||
return mIconProvider.getIcon(info, mIconDpi);
|
||||
}
|
||||
|
||||
public void updateSessionCache(PackageUserKey key, PackageInstaller.SessionInfo info) {
|
||||
|
@ -247,6 +243,15 @@ public class IconCache extends BaseIconCache {
|
|||
+ ",flags_asi:" + FeatureFlags.APP_SEARCH_IMPROVEMENTS.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) {
|
||||
if (mIconProvider.isClockIcon(cacheKey)) {
|
||||
// For clock icon, we always load the dynamic icon
|
||||
return false;
|
||||
}
|
||||
return super.getEntryFromDB(cacheKey, entry, lowRes);
|
||||
}
|
||||
|
||||
public static abstract class IconLoadRequest extends HandlerRunnable {
|
||||
IconLoadRequest(Handler handler, Runnable endRunnable) {
|
||||
super(handler, endRunnable);
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Copyright (C) 2019 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.icons;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.compat.UserManagerCompat;
|
||||
import com.android.launcher3.icons.BitmapInfo.Extender;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Class to handle icon loading from different packages
|
||||
*/
|
||||
public class IconProvider {
|
||||
|
||||
private static final String TAG = "IconProvider";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final String ICON_METADATA_KEY_PREFIX = ".dynamic_icons";
|
||||
|
||||
private static final String SYSTEM_STATE_SEPARATOR = " ";
|
||||
|
||||
// Default value returned if there are problems getting resources.
|
||||
private static final int NO_ID = 0;
|
||||
|
||||
private static final BiFunction<LauncherActivityInfo, Integer, Drawable> LAI_LOADER =
|
||||
LauncherActivityInfo::getIcon;
|
||||
|
||||
private static final BiFunction<ActivityInfo, PackageManager, Drawable> AI_LOADER =
|
||||
ActivityInfo::loadUnbadgedIcon;
|
||||
|
||||
|
||||
private final Context mContext;
|
||||
private final ComponentName mCalendar;
|
||||
private final ComponentName mClock;
|
||||
|
||||
public IconProvider(Context context) {
|
||||
mContext = context;
|
||||
mCalendar = parseComponentOrNull(context, R.string.calendar_component_name);
|
||||
mClock = parseComponentOrNull(context, R.string.clock_component_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds any modification to the provided systemState for dynamic icons. This system state
|
||||
* is used by caches to check for icon invalidation.
|
||||
*/
|
||||
public String getSystemStateForPackage(String systemState, String packageName) {
|
||||
if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
|
||||
return systemState + SYSTEM_STATE_SEPARATOR + getDay();
|
||||
} else {
|
||||
return systemState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the icon for the provided LauncherActivityInfo such that it can be drawn directly
|
||||
* on the UI
|
||||
*/
|
||||
public Drawable getIconForUI(LauncherActivityInfo info, int iconDpi) {
|
||||
Drawable icon = getIcon(info, iconDpi);
|
||||
if (icon instanceof BitmapInfo.Extender) {
|
||||
((Extender) icon).prepareToDrawOnUi();
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the icon for the provided LauncherActivityInfo
|
||||
*/
|
||||
public Drawable getIcon(LauncherActivityInfo info, int iconDpi) {
|
||||
return getIcon(info.getApplicationInfo().packageName, info.getUser(),
|
||||
info, iconDpi, LAI_LOADER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the icon for the provided activity info
|
||||
*/
|
||||
public Drawable getIcon(ActivityInfo info, UserHandle user) {
|
||||
return getIcon(info.applicationInfo.packageName, user, info, mContext.getPackageManager(),
|
||||
AI_LOADER);
|
||||
}
|
||||
|
||||
private <T, P> Drawable getIcon(String packageName, UserHandle user, T obj, P param,
|
||||
BiFunction<T, P, Drawable> loader) {
|
||||
Drawable icon = null;
|
||||
if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
|
||||
icon = loadCalendarDrawable(0);
|
||||
} else if (mClock != null
|
||||
&& mClock.getPackageName().equals(packageName)
|
||||
&& Process.myUserHandle().equals(user)) {
|
||||
icon = loadClockDrawable(0);
|
||||
}
|
||||
return icon == null ? loader.apply(obj, param) : icon;
|
||||
}
|
||||
|
||||
private Drawable loadCalendarDrawable(int iconDpi) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
try {
|
||||
final Bundle metadata = pm.getActivityInfo(
|
||||
mCalendar,
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA)
|
||||
.metaData;
|
||||
final Resources resources = pm.getResourcesForApplication(mCalendar.getPackageName());
|
||||
final int id = getDynamicIconId(metadata, resources);
|
||||
if (id != NO_ID) {
|
||||
if (DEBUG) Log.d(TAG, "Got icon #" + id);
|
||||
return resources.getDrawableForDensity(id, iconDpi, null /* theme */);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Could not get activityinfo or resources for package: "
|
||||
+ mCalendar.getPackageName());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Drawable loadClockDrawable(int iconDpi) {
|
||||
return ClockDrawableWrapper.forPackage(mContext, mClock.getPackageName(), iconDpi);
|
||||
}
|
||||
|
||||
protected boolean isClockIcon(ComponentKey key) {
|
||||
return mClock != null && mClock.equals(key.componentName)
|
||||
&& Process.myUserHandle().equals(key.user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param metadata metadata of the default activity of Calendar
|
||||
* @param resources from the Calendar package
|
||||
* @return the resource id for today's Calendar icon; 0 if resources cannot be found.
|
||||
*/
|
||||
private int getDynamicIconId(Bundle metadata, Resources resources) {
|
||||
if (metadata == null) {
|
||||
return NO_ID;
|
||||
}
|
||||
String key = mCalendar.getPackageName() + ICON_METADATA_KEY_PREFIX;
|
||||
final int arrayId = metadata.getInt(key, NO_ID);
|
||||
if (arrayId == NO_ID) {
|
||||
return NO_ID;
|
||||
}
|
||||
try {
|
||||
return resources.obtainTypedArray(arrayId).getResourceId(getDay(), NO_ID);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "package defines '" + key + "' but corresponding array not found");
|
||||
}
|
||||
return NO_ID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Today's day of the month, zero-indexed.
|
||||
*/
|
||||
private int getDay() {
|
||||
return Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers a callback to listen for calendar icon changes.
|
||||
* The callback receives the packageName for the calendar icon
|
||||
*/
|
||||
public static SafeCloseable registerIconChangeListener(Context context,
|
||||
BiConsumer<String, UserHandle> callback, Handler handler) {
|
||||
ComponentName calendar = parseComponentOrNull(context, R.string.calendar_component_name);
|
||||
ComponentName clock = parseComponentOrNull(context, R.string.clock_component_name);
|
||||
|
||||
if (calendar == null && clock == null) {
|
||||
return () -> { };
|
||||
}
|
||||
|
||||
BroadcastReceiver receiver = new DateTimeChangeReceiver(callback);
|
||||
final IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
|
||||
if (calendar != null) {
|
||||
filter.addAction(Intent.ACTION_TIME_CHANGED);
|
||||
filter.addAction(Intent.ACTION_DATE_CHANGED);
|
||||
}
|
||||
context.registerReceiver(receiver, filter, null, handler);
|
||||
|
||||
return () -> context.unregisterReceiver(receiver);
|
||||
}
|
||||
|
||||
private static class DateTimeChangeReceiver extends BroadcastReceiver {
|
||||
|
||||
private final BiConsumer<String, UserHandle> mCallback;
|
||||
|
||||
DateTimeChangeReceiver(BiConsumer<String, UserHandle> callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
|
||||
ComponentName clock = parseComponentOrNull(context, R.string.clock_component_name);
|
||||
if (clock != null) {
|
||||
mCallback.accept(clock.getPackageName(), Process.myUserHandle());
|
||||
}
|
||||
}
|
||||
|
||||
ComponentName calendar =
|
||||
parseComponentOrNull(context, R.string.calendar_component_name);
|
||||
if (calendar != null) {
|
||||
for (UserHandle user : UserManagerCompat.getInstance(context).getUserProfiles()) {
|
||||
mCallback.accept(calendar.getPackageName(), user);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static ComponentName parseComponentOrNull(Context context, int resId) {
|
||||
String cn = context.getString(resId);
|
||||
return TextUtils.isEmpty(cn) ? null : ComponentName.unflattenFromString(cn);
|
||||
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ import android.content.Context;
|
|||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.launcher3.IconProvider;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.icons.cache.CachingLogic;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
|
@ -57,9 +56,8 @@ public class LauncherActivityCachingLogic
|
|||
@Override
|
||||
public BitmapInfo loadIcon(Context context, LauncherActivityInfo object) {
|
||||
try (LauncherIcons li = LauncherIcons.obtain(context)) {
|
||||
return li.createBadgedIconBitmap(
|
||||
IconProvider.INSTANCE.get(context)
|
||||
.getIcon(object, li.mFillResIconDpi, true /* flattenDrawable */),
|
||||
return li.createBadgedIconBitmap(new IconProvider(context)
|
||||
.getIcon(object, li.mFillResIconDpi),
|
||||
object.getUser(), object.getApplicationInfo().targetSdkVersion);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import com.android.launcher3.FastBitmapDrawable;
|
|||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
|
@ -45,8 +44,6 @@ import java.util.function.Supplier;
|
|||
*/
|
||||
public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
|
||||
|
||||
private static final String EXTRA_BADGEPKG = "badge_package";
|
||||
|
||||
private static final Object sPoolSync = new Object();
|
||||
private static LauncherIcons sPool;
|
||||
private static int sPoolId = 0;
|
||||
|
@ -160,7 +157,7 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
|
|||
|
||||
public ItemInfoWithIcon getShortcutInfoBadge(ShortcutInfo shortcutInfo, IconCache cache) {
|
||||
ComponentName cn = shortcutInfo.getActivity();
|
||||
String badgePkg = getBadgePackage(shortcutInfo);
|
||||
String badgePkg = shortcutInfo.getPackage();
|
||||
boolean hasBadgePkgSet = !badgePkg.equals(shortcutInfo.getPackage());
|
||||
if (cn != null && !hasBadgePkgSet) {
|
||||
// Get the app info for the source activity.
|
||||
|
@ -178,14 +175,4 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
|
|||
return pkgInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private String getBadgePackage(ShortcutInfo si) {
|
||||
String whitelistedPkg = mContext.getString(R.string.shortcutinfo_badgepkg_whitelist);
|
||||
if (whitelistedPkg.equals(si.getPackage())
|
||||
&& si.getExtras() != null
|
||||
&& si.getExtras().containsKey(EXTRA_BADGEPKG)) {
|
||||
return si.getExtras().getString(EXTRA_BADGEPKG);
|
||||
}
|
||||
return si.getPackage();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -415,7 +415,7 @@ public class FloatingIconView extends View implements
|
|||
int width = isFolderIcon ? originalView.getWidth() : (int) pos.width();
|
||||
int height = isFolderIcon ? originalView.getHeight() : (int) pos.height();
|
||||
if (supportsAdaptiveIcons) {
|
||||
drawable = getFullDrawable(l, info, width, height, false, sTmpObjArray);
|
||||
drawable = getFullDrawable(l, info, width, height, sTmpObjArray);
|
||||
if (drawable instanceof AdaptiveIconDrawable) {
|
||||
badge = getBadge(l, info, sTmpObjArray[0]);
|
||||
} else {
|
||||
|
@ -428,7 +428,7 @@ public class FloatingIconView extends View implements
|
|||
// Similar to DragView, we simply use the BubbleTextView icon here.
|
||||
drawable = btvIcon;
|
||||
} else {
|
||||
drawable = getFullDrawable(l, info, width, height, false, sTmpObjArray);
|
||||
drawable = getFullDrawable(l, info, width, height, sTmpObjArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package com.android.launcher3.widget;
|
||||
|
||||
import static com.android.launcher3.FastBitmapDrawable.newIcon;
|
||||
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
|
@ -36,7 +39,6 @@ import com.android.launcher3.FastBitmapDrawable;
|
|||
import com.android.launcher3.ItemInfoWithIcon;
|
||||
import com.android.launcher3.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
|
||||
import com.android.launcher3.model.PackageItemInfo;
|
||||
|
@ -133,19 +135,17 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
|
|||
// 1) App icon in the center
|
||||
// 2) Preload icon in the center
|
||||
// 3) Setup icon in the center and app icon in the top right corner.
|
||||
DrawableFactory drawableFactory = DrawableFactory.INSTANCE.get(getContext());
|
||||
if (mDisabledForSafeMode) {
|
||||
FastBitmapDrawable disabledIcon = drawableFactory.newIcon(getContext(), info);
|
||||
FastBitmapDrawable disabledIcon = newIcon(getContext(), info);
|
||||
disabledIcon.setIsDisabled(true);
|
||||
mCenterDrawable = disabledIcon;
|
||||
mSettingIconDrawable = null;
|
||||
} else if (isReadyForClickSetup()) {
|
||||
mCenterDrawable = drawableFactory.newIcon(getContext(), info);
|
||||
mCenterDrawable = newIcon(getContext(), info);
|
||||
mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
|
||||
updateSettingColor(info.bitmap.color);
|
||||
} else {
|
||||
mCenterDrawable = DrawableFactory.INSTANCE.get(getContext())
|
||||
.newPendingIcon(getContext(), info);
|
||||
mCenterDrawable = newPendingIcon(getContext(), info);
|
||||
mSettingIconDrawable = null;
|
||||
applyState();
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ import com.android.launcher3.R;
|
|||
import com.android.launcher3.SimpleOnStylusPressListener;
|
||||
import com.android.launcher3.StylusEventHelper;
|
||||
import com.android.launcher3.WidgetPreviewLoader;
|
||||
import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.icons.BaseIconFactory;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
|
||||
|
@ -182,10 +181,8 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
|||
return;
|
||||
}
|
||||
if (bitmap != null) {
|
||||
mWidgetImage.setBitmap(bitmap,
|
||||
DrawableFactory.INSTANCE.get(getContext()).getBadgeForUser(mItem.user,
|
||||
getContext(), BaseIconFactory.getBadgeSizeForIconSize(
|
||||
mDeviceProfile.allAppsIconSizePx)));
|
||||
mWidgetImage.setBitmap(bitmap, mWidgetPreviewLoader.getBadgeForUser(mItem.user,
|
||||
BaseIconFactory.getBadgeSizeForIconSize(mDeviceProfile.allAppsIconSizePx)));
|
||||
if (mAnimatePreview) {
|
||||
mWidgetImage.setAlpha(0f);
|
||||
ViewPropertyAnimator anim = mWidgetImage.animate();
|
||||
|
|
Loading…
Reference in New Issue