diff --git a/res/drawable/bg_deferred_app_widget.xml b/res/drawable/bg_deferred_app_widget.xml new file mode 100644 index 0000000000..07bae480b2 --- /dev/null +++ b/res/drawable/bg_deferred_app_widget.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index 1e95333ff2..7648e30375 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -19,6 +19,7 @@ import android.view.ViewGroup; import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.util.FocusLogic; +import com.android.launcher3.widget.LauncherAppWidgetHostView; public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener { private static final int SNAP_DURATION = 150; diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 01b6ca987e..4087df1b10 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -60,6 +60,7 @@ import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.ParcelableSparseArray; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.LauncherAppWidgetHostView; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 44660ecc10..9eaa6c73a4 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -29,8 +29,6 @@ import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; -import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS; -import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS; import android.Manifest; import android.animation.Animator; @@ -127,15 +125,16 @@ import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.PendingRequestArgs; -import com.android.launcher3.util.RunnableWithId; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.ViewOnDrawExecutor; +import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; +import com.android.launcher3.widget.PendingAppWidgetHostView; import com.android.launcher3.widget.WidgetAddFlowHandler; import com.android.launcher3.widget.WidgetHostViewLoader; import com.android.launcher3.widget.WidgetListRowEntry; @@ -237,9 +236,7 @@ public class Launcher extends BaseActivity @Thunk boolean mWorkspaceLoading = true; private boolean mPaused = true; - private boolean mOnResumeNeedsLoad; - private final ArrayList mBindOnResumeCallbacks = new ArrayList<>(); private OnResumeCallback mOnResumeCallback; private ViewOnDrawExecutor mPendingExecutor; @@ -811,20 +808,6 @@ public class Launcher extends BaseActivity mAppLaunchSuccess = false; getUserEventDispatcher().resetElapsedSessionMillis(); mPaused = false; - if (mOnResumeNeedsLoad) { - setWorkspaceLoading(true); - mModel.startLoader(getCurrentWorkspaceScreen()); - mOnResumeNeedsLoad = false; - } - if (mBindOnResumeCallbacks.size() > 0) { - // We might have postponed some bind calls until onResume (see waitUntilResume) -- - // execute them here - for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) { - mBindOnResumeCallbacks.get(i).run(); - } - mBindOnResumeCallbacks.clear(); - } - setOnResumeCallback(null); // Process any items that were added while Launcher was away. InstallShortcutReceiver.disableAndFlushInstallQueue( @@ -1161,20 +1144,12 @@ public class Launcher extends BaseActivity }; public void updateIconBadges(final Set updatedBadges) { - Runnable r = new Runnable() { - @Override - public void run() { - mWorkspace.updateIconBadges(updatedBadges); - mAppsView.updateIconBadges(updatedBadges); + mWorkspace.updateIconBadges(updatedBadges); + mAppsView.updateIconBadges(updatedBadges); - PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(Launcher.this); - if (popup != null) { - popup.updateNotificationHeader(updatedBadges); - } - } - }; - if (!waitUntilResume(r)) { - r.run(); + PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(Launcher.this); + if (popup != null) { + popup.updateNotificationHeader(updatedBadges); } } @@ -2156,33 +2131,6 @@ public class Launcher extends BaseActivity return result; } - /** - * If the activity is currently paused, signal that we need to run the passed Runnable - * in onResume. - * - * This needs to be called from incoming places where resources might have been loaded - * while the activity is paused. That is because the Configuration (e.g., rotation) might be - * wrong when we're not running, and if the activity comes back to what the configuration was - * when we were paused, activity is not restarted. - * - * Implementation of the method from LauncherModel.Callbacks. - * - * @return {@code true} if we are currently paused. The caller might be able to skip some work - */ - @Thunk boolean waitUntilResume(Runnable run) { - if (mPaused) { - if (LOGD) Log.d(TAG, "Deferring update until onResume"); - if (run instanceof RunnableWithId) { - // Remove any runnables which have the same id - while (mBindOnResumeCallbacks.remove(run)) { } - } - mBindOnResumeCallbacks.add(run); - return true; - } else { - return false; - } - } - public void setOnResumeCallback(OnResumeCallback callback) { if (mOnResumeCallback != null) { mOnResumeCallback.onLauncherResume(); @@ -2190,31 +2138,6 @@ public class Launcher extends BaseActivity mOnResumeCallback = callback; } - /** - * If the activity is currently paused, signal that we need to re-run the loader - * in onResume. - * - * This needs to be called from incoming places where resources might have been loaded - * while we are paused. That is becaues the Configuration might be wrong - * when we're not running, and if it comes back to what it was when we - * were paused, we are not restarted. - * - * Implementation of the method from LauncherModel.Callbacks. - * - * @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"); - mOnResumeNeedsLoad = true; - return true; - } else { - return false; - } - } - /** * Implementation of the method from LauncherModel.Callbacks. */ @@ -2233,7 +2156,6 @@ public class Launcher extends BaseActivity */ @Override public void clearPendingBinds() { - mBindOnResumeCallbacks.clear(); if (mPendingExecutor != null) { mPendingExecutor.markCompleted(); mPendingExecutor = null; @@ -2297,18 +2219,8 @@ public class Launcher extends BaseActivity } @Override - public void bindAppsAdded(final ArrayList newScreens, - final ArrayList addNotAnimated, - final ArrayList addAnimated) { - Runnable r = new Runnable() { - public void run() { - bindAppsAdded(newScreens, addNotAnimated, addAnimated); - } - }; - if (waitUntilResume(r)) { - return; - } - + public void bindAppsAdded(ArrayList newScreens, ArrayList addNotAnimated, + ArrayList addAnimated) { // Add the new screens if (newScreens != null) { bindAddScreens(newScreens); @@ -2334,15 +2246,6 @@ public class Launcher extends BaseActivity */ @Override public void bindItems(final List items, final boolean forceAnimateIcons) { - Runnable r = new Runnable() { - public void run() { - bindItems(items, forceAnimateIcons); - } - }; - if (waitUntilResume(r)) { - return; - } - // Get the list of added items and intersect them with the set of items here final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); final Collection bounceAnims = new ArrayList<>(); @@ -2585,7 +2488,7 @@ public class Launcher extends BaseActivity } if (((PendingAppWidgetHostView) view).isReinflateIfNeeded()) { - view.reinflate(); + view.reInflate(); } getModelWriter().updateItemInDatabase(info); @@ -2613,27 +2516,11 @@ public class Launcher extends BaseActivity @Override public void finishFirstPageBind(final ViewOnDrawExecutor executor) { - Runnable r = new Runnable() { - public void run() { - finishFirstPageBind(executor); - } - }; - if (waitUntilResume(r)) { - return; - } - - Runnable onComplete = new Runnable() { - @Override - public void run() { - if (executor != null) { - executor.onLoadAnimationCompleted(); - } - } - }; if (mDragLayer.getAlpha() < 1) { - mDragLayer.animate().alpha(1).withEndAction(onComplete).start(); - } else { - onComplete.run(); + mDragLayer.animate().alpha(1).withEndAction( + executor == null ? null : executor::onLoadAnimationCompleted).start(); + } else if (executor != null) { + executor.onLoadAnimationCompleted(); } } @@ -2643,10 +2530,6 @@ public class Launcher extends BaseActivity * Implementation of the method from LauncherModel.Callbacks. */ public void finishBindingItems() { - Runnable r = this::finishBindingItems; - if (waitUntilResume(r)) { - return; - } TraceHelper.beginSection("finishBindingItems"); mWorkspace.restoreInstanceStateForRemainingPages(); @@ -2687,21 +2570,12 @@ public class Launcher extends BaseActivity * * Implementation of the method from LauncherModel.Callbacks. */ - public void bindAllApplications(final ArrayList apps) { - Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) { - public void run() { - bindAllApplications(apps); - } - }; - if (waitUntilResume(r)) { - return; - } - + public void bindAllApplications(ArrayList apps) { if (mAppsView != null) { Executor pendingExecutor = getPendingExecutor(); if (pendingExecutor != null && !isInState(ALL_APPS)) { // Wait until the fade in animation has finished before setting all apps list. - pendingExecutor.execute(r); + pendingExecutor.execute(() -> bindAllApplications(apps)); return; } @@ -2734,47 +2608,22 @@ public class Launcher extends BaseActivity * * Implementation of the method from LauncherModel.Callbacks. */ - public void bindAppsAddedOrUpdated(final ArrayList apps) { - Runnable r = new Runnable() { - public void run() { - bindAppsAddedOrUpdated(apps); - } - }; - if (waitUntilResume(r)) { - return; - } - + @Override + public void bindAppsAddedOrUpdated(ArrayList apps) { if (mAppsView != null) { mAppsView.addOrUpdateApps(apps); } } @Override - public void bindPromiseAppProgressUpdated(final PromiseAppInfo app) { - Runnable r = new Runnable() { - public void run() { - bindPromiseAppProgressUpdated(app); - } - }; - if (waitUntilResume(r)) { - return; - } - + public void bindPromiseAppProgressUpdated(PromiseAppInfo app) { if (mAppsView != null) { mAppsView.updatePromiseAppProgress(app); } } @Override - public void bindWidgetsRestored(final ArrayList widgets) { - Runnable r = new Runnable() { - public void run() { - bindWidgetsRestored(widgets); - } - }; - if (waitUntilResume(r)) { - return; - } + public void bindWidgetsRestored(ArrayList widgets) { mWorkspace.widgetsRestored(widgets); } @@ -2785,16 +2634,7 @@ public class Launcher extends BaseActivity * @param updated list of shortcuts which have changed. */ @Override - public void bindShortcutsChanged(final ArrayList updated, final UserHandle user) { - Runnable r = new Runnable() { - public void run() { - bindShortcutsChanged(updated, user); - } - }; - if (waitUntilResume(r)) { - return; - } - + public void bindShortcutsChanged(ArrayList updated, final UserHandle user) { if (!updated.isEmpty()) { mWorkspace.updateShortcuts(updated); } @@ -2806,16 +2646,7 @@ public class Launcher extends BaseActivity * Implementation of the method from LauncherModel.Callbacks. */ @Override - public void bindRestoreItemsChange(final HashSet updates) { - Runnable r = new Runnable() { - public void run() { - bindRestoreItemsChange(updates); - } - }; - if (waitUntilResume(r)) { - return; - } - + public void bindRestoreItemsChange(HashSet updates) { mWorkspace.updateRestoreItems(updates); } @@ -2828,29 +2659,12 @@ public class Launcher extends BaseActivity */ @Override public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) { - Runnable r = new Runnable() { - public void run() { - bindWorkspaceComponentsRemoved(matcher); - } - }; - if (waitUntilResume(r)) { - return; - } mWorkspace.removeItemsByMatcher(matcher); mDragController.onAppsRemoved(matcher); } @Override public void bindAppInfosRemoved(final ArrayList appInfos) { - Runnable r = new Runnable() { - public void run() { - bindAppInfosRemoved(appInfos); - } - }; - if (waitUntilResume(r)) { - return; - } - // Update AllApps if (mAppsView != null) { mAppsView.removeApps(appInfos); @@ -2860,16 +2674,6 @@ public class Launcher extends BaseActivity @Override public void bindAllWidgets(final ArrayList allWidgets) { mPopupDataProvider.setAllWidgets(allWidgets); - Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_WIDGETS) { - @Override - public void run() { - bindAllWidgets(allWidgets); - } - }; - if (waitUntilResume(r)) { - return; - } - AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this); if (topView != null) { topView.onWidgetsBound(); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 0136c7087f..a46692b0b5 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -27,6 +27,7 @@ import android.util.Log; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.util.ConfigMonitor; import com.android.launcher3.util.Preconditions; @@ -39,6 +40,8 @@ import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING; public class LauncherAppState { + public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher"; + // We do not need any synchronization for this variable as its only written on UI thread. private static LauncherAppState INSTANCE; @@ -103,6 +106,10 @@ public class LauncherAppState { filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED); + if (FeatureFlags.IS_DOGFOOD_BUILD) { + filter.addAction(ACTION_FORCE_ROLOAD); + } + mContext.registerReceiver(mModel, filter); UserManagerCompat.getInstance(mContext).enableAndResetCache(); new ConfigMonitor(mContext).register(); diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java index 9aa74b38d5..7bc713922b 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/LauncherAppWidgetHost.java @@ -26,11 +26,14 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.os.Handler; +import android.util.Log; import android.util.SparseArray; import android.view.LayoutInflater; import android.widget.Toast; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.widget.DeferredAppWidgetHostView; +import com.android.launcher3.widget.LauncherAppWidgetHostView; import java.util.ArrayList; @@ -84,6 +87,14 @@ public class LauncherAppWidgetHost extends AppWidgetHost { // have been established by this point, and we will end up populating the // widgets upon bind anyway. See issue 14255011 for more context. } + + // We go in reverse order and inflate any deferred widget + for (int i = mViews.size() - 1; i >= 0; i--) { + LauncherAppWidgetHostView view = mViews.valueAt(i); + if (view instanceof DeferredAppWidgetHostView) { + view.reInflate(); + } + } } @Override @@ -178,6 +189,11 @@ public class LauncherAppWidgetHost extends AppWidgetHost { inflater.inflate(appWidget.initialLayout, lahv); lahv.setAppWidget(0, appWidget); return lahv; + } else if ((mFlags & FLAG_LISTENING) == 0) { + DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context); + view.setAppWidget(appWidgetId, appWidget); + mViews.put(appWidgetId, view); + return view; } else { try { return super.createView(context, appWidgetId, appWidget); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 469c5f1c09..35bf9e9ee8 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -16,6 +16,9 @@ package com.android.launcher3; +import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD; +import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD; + import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProviderOperation; @@ -37,6 +40,7 @@ import android.util.Pair; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.model.AddWorkspaceItemsTask; import com.android.launcher3.model.BgDataModel; @@ -135,7 +139,6 @@ public class LauncherModel extends BroadcastReceiver }; public interface Callbacks { - public boolean setLoadOnResume(); public int getCurrentWorkspaceScreen(); public void clearPendingBinds(); public void startBinding(); @@ -405,6 +408,8 @@ public class LauncherModel extends BroadcastReceiver enqueueModelUpdateTask(new UserLockStateChangedTask(user)); } } + } else if (IS_DOGFOOD_BUILD && ACTION_FORCE_ROLOAD.equals(action)) { + forceReload(); } } @@ -419,25 +424,11 @@ public class LauncherModel extends BroadcastReceiver mModelLoaded = false; } - // Do this here because if the launcher activity is running it will be restarted. - // If it's not running startLoaderFromBackground will merely tell it that it needs - // to reload. - startLoaderFromBackground(); - } - - /** - * When the launcher is in the background, it's possible for it to miss paired - * configuration changes. So whenever we trigger the loader from the background - * tell the launcher that it needs to re-run the loader when it comes back instead - * of doing it now. - */ - public void startLoaderFromBackground() { + // Start the loader if launcher is already running, otherwise the loader will run, + // the next time launcher starts Callbacks callbacks = getCallback(); if (callbacks != null) { - // Only actually run the loader if they're not paused. - if (!callbacks.setLoadOnResume()) { - startLoader(callbacks.getCurrentWorkspaceScreen()); - } + startLoader(callbacks.getCurrentWorkspaceScreen()); } } diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index 841c0cd57a..1a63326dd2 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -23,6 +23,7 @@ import android.view.View; import android.view.ViewGroup; import com.android.launcher3.CellLayout.ContainerType; +import com.android.launcher3.widget.LauncherAppWidgetHostView; public class ShortcutAndWidgetContainer extends ViewGroup { static final String TAG = "ShortcutAndWidgetContainer"; diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 417366d18a..efafb9c424 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -88,8 +88,10 @@ import com.android.launcher3.util.LongArrayMap; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.WallpaperOffsetInterpolator; +import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; +import com.android.launcher3.widget.PendingAppWidgetHostView; import java.util.ArrayList; import java.util.HashSet; @@ -3510,7 +3512,7 @@ public class Workspace extends PagedView return false; }); for (PendingAppWidgetHostView view : views) { - view.reinflate(); + view.reInflate(); } } diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index 512db721e8..3b6fea9465 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -21,20 +21,17 @@ import com.android.launcher3.AppWidgetResizeFrame; import com.android.launcher3.BubbleTextView; import com.android.launcher3.ButtonDropTarget; import com.android.launcher3.CellLayout; -import com.android.launcher3.DeleteDropTarget; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.FolderInfo; -import com.android.launcher3.InfoDropTarget; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppWidgetHostView; +import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; -import com.android.launcher3.UninstallDropTarget; import com.android.launcher3.Workspace; import com.android.launcher3.dragndrop.DragController.DragListener; import com.android.launcher3.dragndrop.DragOptions; diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java index 902906f4b7..6a328e9230 100644 --- a/src/com/android/launcher3/graphics/DragPreviewProvider.java +++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java @@ -31,7 +31,7 @@ import android.view.View; import com.android.launcher3.BubbleTextView; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppWidgetHostView; +import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.R; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.FolderIcon; diff --git a/src/com/android/launcher3/util/RunnableWithId.java b/src/com/android/launcher3/util/RunnableWithId.java deleted file mode 100644 index 030eb09ff3..0000000000 --- a/src/com/android/launcher3/util/RunnableWithId.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2017 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.util; - -/** - * A runnable with an id associated which is used for equality check. - */ -public abstract class RunnableWithId implements Runnable { - - public static final int RUNNABLE_ID_BIND_APPS = 1; - public static final int RUNNABLE_ID_BIND_WIDGETS = 2; - - public final int id; - - public RunnableWithId(int id) { - this.id = id; - } - - @Override - public boolean equals(Object obj) { - return obj instanceof RunnableWithId && ((RunnableWithId) obj).id == id; - } -} diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java new file mode 100644 index 0000000000..37e5efcb78 --- /dev/null +++ b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 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.widget; + +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.TypedValue; +import android.widget.RemoteViews; + +import com.android.launcher3.R; + +/** + * A widget host views created while the host has not bind to the system service. + */ +public class DeferredAppWidgetHostView extends LauncherAppWidgetHostView { + + private final TextPaint mPaint; + private Layout mSetupTextLayout; + + public DeferredAppWidgetHostView(Context context) { + super(context); + setWillNotDraw(false); + + mPaint = new TextPaint(); + mPaint.setColor(Color.WHITE); + mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, + mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics())); + setBackgroundResource(R.drawable.bg_deferred_app_widget); + } + + @Override + public void updateAppWidget(RemoteViews remoteViews) { + // Not allowed + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + AppWidgetProviderInfo info = getAppWidgetInfo(); + if (info == null || TextUtils.isEmpty(info.label)) { + return; + } + + // Use double padding so that there is extra space between background and text + int availableWidth = getMeasuredWidth() - 2 * (getPaddingLeft() + getPaddingRight()); + if (mSetupTextLayout != null && mSetupTextLayout.getText().equals(info.label) + && mSetupTextLayout.getWidth() == availableWidth) { + return; + } + mSetupTextLayout = new StaticLayout(info.label, mPaint, availableWidth, + Layout.Alignment.ALIGN_CENTER, 1, 0, true); + } + + @Override + protected void onDraw(Canvas canvas) { + if (mSetupTextLayout != null) { + canvas.translate(getPaddingLeft() * 2, + (getHeight() - mSetupTextLayout.getHeight()) / 2); + mSetupTextLayout.draw(canvas); + } + } +} diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java similarity index 92% rename from src/com/android/launcher3/LauncherAppWidgetHostView.java rename to src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 6f953e5f0a..0b1474a037 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.launcher3; +package com.android.launcher3.widget; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; @@ -37,6 +37,15 @@ import android.widget.AdapterView; import android.widget.Advanceable; import android.widget.RemoteViews; +import com.android.launcher3.CheckLongPressHelper; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.R; +import com.android.launcher3.SimpleOnStylusPressListener; +import com.android.launcher3.StylusEventHelper; +import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener; @@ -59,14 +68,10 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView private final CheckLongPressHelper mLongPressHelper; private final StylusEventHelper mStylusEventHelper; - private final Launcher mLauncher; - - private static final int DONT_REINFLATE = 0; - private static final int REINFLATE_ON_RESUME = 1; - private static final int REINFLATE_ON_CONFIG_CHANGE = 2; + protected final Launcher mLauncher; @ViewDebug.ExportedProperty(category = "launcher") - private int mReinflateStatus; + private boolean mReinflateOnConfigChange; private float mSlop; @@ -128,12 +133,7 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView // Consequently, the widgets will be inflated for the orientation of the foreground activity // (framework issue). On resuming, we ensure that any widgets are inflated for the current // orientation. - if (mReinflateStatus == DONT_REINFLATE && !isSameOrientation()) { - mReinflateStatus = REINFLATE_ON_RESUME; - if (!mLauncher.waitUntilResume(new ReInflateRunnable())) { - mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE; - } - } + mReinflateOnConfigChange = !isSameOrientation(); } private boolean isSameOrientation() { @@ -485,40 +485,20 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - if (mReinflateStatus == REINFLATE_ON_CONFIG_CHANGE) { - // We are finally in the same orientation - reinflateIfNecessary(); + // Only reinflate when the final configuration is same as the required configuration + if (mReinflateOnConfigChange && isSameOrientation()) { + mReinflateOnConfigChange = false; + if (isAttachedToWindow()) { + reInflate(); + } } } - private void reinflateIfNecessary() { - if (!isSameOrientation()) { - // We cannot reinflate yet, wait until next config change - mReinflateStatus = REINFLATE_ON_CONFIG_CHANGE; - return; - } - - mReinflateStatus = DONT_REINFLATE; - if (isAttachedToWindow()) { - LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); - reinflate(); - } - } - - public void reinflate() { + public void reInflate() { LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); // Remove and rebind the current widget (which was inflated in the wrong // orientation), but don't delete it from the database mLauncher.removeItem(this, info, false /* deleteFromDb */); mLauncher.bindAppWidget(info); } - - private class ReInflateRunnable implements Runnable { - @Override - public void run() { - if (mReinflateStatus == REINFLATE_ON_RESUME) { - reinflateIfNecessary(); - } - } - } } diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java similarity index 96% rename from src/com/android/launcher3/PendingAppWidgetHostView.java rename to src/com/android/launcher3/widget/PendingAppWidgetHostView.java index b86d413185..24bcebb2e1 100644 --- a/src/com/android/launcher3/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.launcher3; +package com.android.launcher3.widget; import android.content.Context; import android.graphics.Bitmap; @@ -32,10 +32,19 @@ import android.view.ContextThemeWrapper; import android.view.View; import android.view.View.OnClickListener; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.FastBitmapDrawable; +import com.android.launcher3.IconCache; import com.android.launcher3.IconCache.ItemInfoUpdateReceiver; +import com.android.launcher3.ItemInfoWithIcon; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.graphics.DrawableFactory; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.util.Themes; +import com.android.launcher3.widget.LauncherAppWidgetHostView; public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implements OnClickListener, ItemInfoUpdateReceiver { @@ -48,7 +57,6 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView private final LauncherAppWidgetInfo mInfo; private final int mStartState; private final boolean mDisabledForSafeMode; - private Launcher mLauncher; private Bitmap mIcon; @@ -64,7 +72,6 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView IconCache cache, boolean disabledForSafeMode) { super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme)); - mLauncher = Launcher.getLauncher(context); mInfo = info; mStartState = info.restoreStatus; mDisabledForSafeMode = disabledForSafeMode; diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java index 87103d7133..32f90a6d88 100644 --- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java @@ -30,12 +30,12 @@ import android.support.test.runner.AndroidJUnit4; import android.support.test.uiautomator.UiSelector; import com.android.launcher3.LauncherAppWidgetHost; -import com.android.launcher3.LauncherAppWidgetHostView; +import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.PendingAppWidgetHostView; +import com.android.launcher3.widget.PendingAppWidgetHostView; import com.android.launcher3.Workspace; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.PackageInstallerCompat;