diff --git a/Android.bp b/Android.bp index 6267e9fa27..0bbb3d2c1e 100644 --- a/Android.bp +++ b/Android.bp @@ -153,6 +153,7 @@ android_library { "androidx.cardview_cardview", "com.google.android.material_material", "iconloader_base", + "view_capture" ], manifest: "AndroidManifest-common.xml", sdk_version: "current", diff --git a/protos/view_capture.proto b/protos/view_capture.proto deleted file mode 100644 index f363f36820..0000000000 --- a/protos/view_capture.proto +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2022 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. - */ - -syntax = "proto2"; - -package com.android.launcher3.view; - -option java_outer_classname = "ViewCaptureData"; - -message ExportedData { - - repeated FrameData frameData = 1; - repeated string classname = 2; -} - -message FrameData { - optional int64 timestamp = 1; - optional ViewNode node = 2; -} - -message ViewNode { - optional int32 classname_index = 1; - optional int32 hashcode = 2; - - repeated ViewNode children = 3; - - optional string id = 4; - optional int32 left = 5; - optional int32 top = 6; - optional int32 width = 7; - optional int32 height = 8; - optional int32 scrollX = 9; - optional int32 scrollY = 10; - - optional float translationX = 11; - optional float translationY = 12; - optional float scaleX = 13 [default = 1]; - optional float scaleY = 14 [default = 1]; - optional float alpha = 15 [default = 1]; - - optional bool willNotDraw = 16; - optional bool clipChildren = 17; - optional int32 visibility = 18; - - optional float elevation = 19; -} diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index df391117fb..eaf577b8cc 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2022 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. @@ -58,6 +58,7 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.hardware.SensorManager; import android.hardware.devicestate.DeviceStateManager; +import android.media.permission.SafeCloseable; import android.os.Bundle; import android.os.CancellationSignal; import android.os.IBinder; @@ -71,10 +72,12 @@ import android.window.SplashScreen; import androidx.annotation.Nullable; +import com.android.app.viewcapture.ViewCapture; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherState; +import com.android.launcher3.LauncherWidgetHolder; import com.android.launcher3.QuickstepAccessibilityDelegate; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; @@ -119,10 +122,8 @@ import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.util.PendingRequestArgs; import com.android.launcher3.util.PendingSplitSelectInfo; import com.android.launcher3.util.RunnableList; -import com.android.launcher3.util.SafeCloseable; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.launcher3.util.TouchController; -import com.android.launcher3.widget.LauncherAppWidgetHost; import com.android.quickstep.OverviewCommandHelper; import com.android.quickstep.RecentsModel; import com.android.quickstep.SystemUiProxy; @@ -135,7 +136,6 @@ import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.util.SplitSelectStateController; import com.android.quickstep.util.TISBindHelper; -import com.android.quickstep.util.ViewCapture; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -402,7 +402,7 @@ public class QuickstepLauncher extends Launcher { super.onDestroy(); mHotseatPredictionController.destroy(); - mViewCapture.close(); + if (mViewCapture != null) mViewCapture.close(); } @Override @@ -487,11 +487,11 @@ public class QuickstepLauncher extends Launcher { return new QuickstepAtomicAnimationFactory(this); } - protected LauncherAppWidgetHost createAppWidgetHost() { - LauncherAppWidgetHost appWidgetHost = super.createAppWidgetHost(); - ApiWrapper.setHostInteractionHandler(appWidgetHost, - new QuickstepInteractionHandler(this)); - return appWidgetHost; + @Override + protected LauncherWidgetHolder createAppWidgetHolder() { + LauncherWidgetHolder appWidgetHolder = super.createAppWidgetHolder(); + appWidgetHolder.setInteractionHandler(new QuickstepInteractionHandler(this)); + return appWidgetHolder; } @Override @@ -503,7 +503,9 @@ public class QuickstepLauncher extends Launcher { } addMultiWindowModeChangedListener(mDepthController); initUnfoldTransitionProgressProvider(); - mViewCapture = ViewCapture.INSTANCE.get(this).startCapture(getWindow()); + if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { + mViewCapture = ViewCapture.getInstance().startCapture(getWindow()); + } } @Override diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 80db362b09..e9f9d80e01 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2022 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. @@ -67,6 +67,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; +import com.android.app.viewcapture.ViewCapture; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -103,7 +104,6 @@ import com.android.quickstep.util.ActiveGestureLog.CompoundString; import com.android.quickstep.util.ProtoTracer; import com.android.quickstep.util.ProxyScreenStatusProvider; import com.android.quickstep.util.SplitScreenBounds; -import com.android.quickstep.util.ViewCapture; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -1238,7 +1238,9 @@ public class TouchInteractionService extends Service } mTaskbarManager.dumpLogs("", pw); - ViewCapture.INSTANCE.get(this).dump(pw, fd); + if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { + ViewCapture.getInstance().dump(pw, fd, this); + } } } diff --git a/quickstep/src/com/android/quickstep/util/ViewCapture.java b/quickstep/src/com/android/quickstep/util/ViewCapture.java deleted file mode 100644 index ba7d7f557c..0000000000 --- a/quickstep/src/com/android/quickstep/util/ViewCapture.java +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Copyright (C) 2022 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 static com.android.launcher3.util.Executors.MAIN_EXECUTOR; -import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; -import static com.android.launcher3.util.Executors.createAndStartNewLooper; - -import static java.util.stream.Collectors.toList; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Looper; -import android.os.Process; -import android.os.SystemClock; -import android.os.Trace; -import android.text.TextUtils; -import android.util.Base64; -import android.util.Base64OutputStream; -import android.util.Log; -import android.util.Pair; -import android.util.SparseArray; -import android.view.View; -import android.view.View.OnAttachStateChangeListener; -import android.view.ViewGroup; -import android.view.ViewTreeObserver.OnDrawListener; -import android.view.Window; - -import androidx.annotation.UiThread; -import androidx.annotation.WorkerThread; - -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.util.LooperExecutor; -import com.android.launcher3.util.MainThreadInitializedObject; -import com.android.launcher3.util.SafeCloseable; -import com.android.launcher3.view.ViewCaptureData.ExportedData; -import com.android.launcher3.view.ViewCaptureData.FrameData; -import com.android.launcher3.view.ViewCaptureData.ViewNode; - -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.concurrent.FutureTask; -import java.util.function.Consumer; -import java.util.zip.GZIPOutputStream; - -/** - * Utility class for capturing view data every frame - */ -public class ViewCapture { - - private static final String TAG = "ViewCapture"; - - // These flags are copies of two private flags in the View class. - private static final int PFLAG_INVALIDATED = 0x80000000; - private static final int PFLAG_DIRTY_MASK = 0x00200000; - - // Number of frames to keep in memory - private static final int MEMORY_SIZE = 2000; - // Initial size of the reference pool. This is at least be 5 * total number of views in - // Launcher. This allows the first free frames avoid object allocation during view capture. - private static final int INIT_POOL_SIZE = 300; - - public static final MainThreadInitializedObject INSTANCE = - new MainThreadInitializedObject<>(ViewCapture::new); - - private final List mListeners = new ArrayList<>(); - - private final Context mContext; - private final Executor mExecutor; - - // Pool used for capturing view tree on the UI thread. - private ViewRef mPool = new ViewRef(); - - private ViewCapture(Context context) { - mContext = context; - if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { - Looper looper = createAndStartNewLooper("ViewCapture", - Process.THREAD_PRIORITY_FOREGROUND); - mExecutor = new LooperExecutor(looper); - mExecutor.execute(this::initPool); - } else { - mExecutor = UI_HELPER_EXECUTOR; - } - } - - @UiThread - private void addToPool(ViewRef start, ViewRef end) { - end.next = mPool; - mPool = start; - } - - @WorkerThread - private void initPool() { - ViewRef start = new ViewRef(); - ViewRef current = start; - - for (int i = 0; i < INIT_POOL_SIZE; i++) { - current.next = new ViewRef(); - current = current.next; - } - - ViewRef finalCurrent = current; - MAIN_EXECUTOR.execute(() -> addToPool(start, finalCurrent)); - } - - /** - * Attaches the ViewCapture to the provided window and returns a handle to detach the listener - */ - public SafeCloseable startCapture(Window window) { - String title = window.getAttributes().getTitle().toString(); - String name = TextUtils.isEmpty(title) ? window.toString() : title; - return startCapture(window.getDecorView(), name); - } - - /** - * Attaches the ViewCapture to the provided window and returns a handle to detach the listener - */ - public SafeCloseable startCapture(View view, String name) { - if (!FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { - return () -> { }; - } - - WindowListener listener = new WindowListener(view, name); - mExecutor.execute(() -> MAIN_EXECUTOR.execute(listener::attachToRoot)); - mListeners.add(listener); - return () -> { - mListeners.remove(listener); - listener.destroy(); - }; - } - - /** - * Dumps all the active view captures - */ - public void dump(PrintWriter writer, FileDescriptor out) { - if (!FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { - return; - } - ViewIdProvider idProvider = new ViewIdProvider(mContext.getResources()); - - // Collect all the tasks first so that all the tasks are posted on the executor - List>> tasks = mListeners.stream() - .map(l -> { - FutureTask task = - new FutureTask(() -> l.dumpToProto(idProvider)); - mExecutor.execute(task); - return Pair.create(l.name, task); - }) - .collect(toList()); - - tasks.forEach(pair -> { - writer.println(); - writer.println(" ContinuousViewCapture:"); - writer.println(" window " + pair.first + ":"); - writer.println(" pkg:" + mContext.getPackageName()); - writer.print(" data:"); - writer.flush(); - try (OutputStream os = new FileOutputStream(out)) { - ExportedData data = pair.second.get(); - OutputStream encodedOS = new GZIPOutputStream(new Base64OutputStream(os, - Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP)); - data.writeTo(encodedOS); - encodedOS.close(); - os.flush(); - } catch (Exception e) { - Log.e(TAG, "Error capturing proto", e); - } - writer.println(); - writer.println("--end--"); - }); - } - - private class WindowListener implements OnDrawListener { - - private final View mRoot; - public final String name; - - private final ViewRef mViewRef = new ViewRef(); - - private int mFrameIndexBg = -1; - private boolean mIsFirstFrame = true; - private final long[] mFrameTimesBg = new long[MEMORY_SIZE]; - private final ViewPropertyRef[] mNodesBg = new ViewPropertyRef[MEMORY_SIZE]; - - private boolean mDestroyed = false; - private final Consumer mCaptureCallback = this::captureViewPropertiesBg; - - WindowListener(View view, String name) { - mRoot = view; - this.name = name; - } - - @Override - public void onDraw() { - Trace.beginSection("view_capture"); - captureViewTree(mRoot, mViewRef); - ViewRef captured = mViewRef.next; - if (captured != null) { - captured.callback = mCaptureCallback; - captured.creationTime = SystemClock.uptimeMillis(); - mExecutor.execute(captured); - } - mIsFirstFrame = false; - Trace.endSection(); - } - - /** - * Captures the View property on the background thread, and transfer all the ViewRef objects - * back to the pool - */ - @WorkerThread - private void captureViewPropertiesBg(ViewRef viewRefStart) { - long time = viewRefStart.creationTime; - mFrameIndexBg++; - if (mFrameIndexBg >= MEMORY_SIZE) { - mFrameIndexBg = 0; - } - mFrameTimesBg[mFrameIndexBg] = time; - - ViewPropertyRef recycle = mNodesBg[mFrameIndexBg]; - - ViewPropertyRef resultStart = null; - ViewPropertyRef resultEnd = null; - - ViewRef viewRefEnd = viewRefStart; - while (viewRefEnd != null) { - ViewPropertyRef propertyRef = recycle; - if (propertyRef == null) { - propertyRef = new ViewPropertyRef(); - } else { - recycle = recycle.next; - propertyRef.next = null; - } - - ViewPropertyRef copy = null; - if (viewRefEnd.childCount < 0) { - copy = findInLastFrame(viewRefEnd.view.hashCode()); - viewRefEnd.childCount = (copy != null) ? copy.childCount : 0; - } - viewRefEnd.transferTo(propertyRef); - - if (resultStart == null) { - resultStart = propertyRef; - resultEnd = resultStart; - } else { - resultEnd.next = propertyRef; - resultEnd = resultEnd.next; - } - - if (copy != null) { - int pending = copy.childCount; - while (pending > 0) { - copy = copy.next; - pending = pending - 1 + copy.childCount; - - propertyRef = recycle; - if (propertyRef == null) { - propertyRef = new ViewPropertyRef(); - } else { - recycle = recycle.next; - propertyRef.next = null; - } - - copy.transferTo(propertyRef); - - resultEnd.next = propertyRef; - resultEnd = resultEnd.next; - } - } - - if (viewRefEnd.next == null) { - // The compiler will complain about using a non-final variable from - // an outer class in a lambda if we pass in viewRefEnd directly. - final ViewRef finalViewRefEnd = viewRefEnd; - MAIN_EXECUTOR.execute(() -> addToPool(viewRefStart, finalViewRefEnd)); - break; - } - viewRefEnd = viewRefEnd.next; - } - mNodesBg[mFrameIndexBg] = resultStart; - } - - private ViewPropertyRef findInLastFrame(int hashCode) { - int lastFrameIndex = (mFrameIndexBg == 0) ? MEMORY_SIZE - 1 : mFrameIndexBg - 1; - ViewPropertyRef viewPropertyRef = mNodesBg[lastFrameIndex]; - while (viewPropertyRef != null && viewPropertyRef.hashCode != hashCode) { - viewPropertyRef = viewPropertyRef.next; - } - return viewPropertyRef; - } - - void attachToRoot() { - if (mRoot.isAttachedToWindow()) { - mRoot.getViewTreeObserver().addOnDrawListener(this); - } else { - mRoot.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - if (!mDestroyed) { - mRoot.getViewTreeObserver().addOnDrawListener(WindowListener.this); - } - mRoot.removeOnAttachStateChangeListener(this); - } - - @Override - public void onViewDetachedFromWindow(View v) { } - }); - } - } - - void destroy() { - mRoot.getViewTreeObserver().removeOnDrawListener(this); - mDestroyed = true; - } - - @WorkerThread - private ExportedData dumpToProto(ViewIdProvider idProvider) { - ExportedData.Builder dataBuilder = ExportedData.newBuilder(); - ArrayList classList = new ArrayList<>(); - - int size = (mNodesBg[MEMORY_SIZE - 1] == null) ? mFrameIndexBg + 1 : MEMORY_SIZE; - for (int i = size - 1; i >= 0; i--) { - int index = (MEMORY_SIZE + mFrameIndexBg - i) % MEMORY_SIZE; - ViewNode.Builder nodeBuilder = ViewNode.newBuilder(); - mNodesBg[index].toProto(idProvider, classList, nodeBuilder); - dataBuilder.addFrameData(FrameData.newBuilder() - .setNode(nodeBuilder) - .setTimestamp(mFrameTimesBg[index])); - } - return dataBuilder - .addAllClassname(classList.stream().map(Class::getName).collect(toList())) - .build(); - } - - private ViewRef captureViewTree(View view, ViewRef start) { - ViewRef ref; - if (mPool != null) { - ref = mPool; - mPool = mPool.next; - ref.next = null; - } else { - ref = new ViewRef(); - } - ref.view = view; - start.next = ref; - if (view instanceof ViewGroup) { - ViewGroup parent = (ViewGroup) view; - // If a view has not changed since the last frame, we will copy - // its children from the last processed frame's data. - if ((view.mPrivateFlags & (PFLAG_INVALIDATED | PFLAG_DIRTY_MASK)) == 0 - && !mIsFirstFrame) { - // A negative child count is the signal to copy this view from the last frame. - ref.childCount = -parent.getChildCount(); - return ref; - } - ViewRef result = ref; - int childCount = ref.childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - result = captureViewTree(parent.getChildAt(i), result); - } - return result; - } else { - ref.childCount = 0; - return ref; - } - } - } - - private static class ViewPropertyRef { - // We store reference in memory to avoid generating and storing too many strings - public Class clazz; - public int hashCode; - public int childCount = 0; - - public int id; - public int left, top, right, bottom; - public int scrollX, scrollY; - - public float translateX, translateY; - public float scaleX, scaleY; - public float alpha; - public float elevation; - - public int visibility; - public boolean willNotDraw; - public boolean clipChildren; - - public ViewPropertyRef next; - - public void transferTo(ViewPropertyRef out) { - out.clazz = this.clazz; - out.hashCode = this.hashCode; - out.childCount = this.childCount; - out.id = this.id; - out.left = this.left; - out.top = this.top; - out.right = this.right; - out.bottom = this.bottom; - out.scrollX = this.scrollX; - out.scrollY = this.scrollY; - out.scaleX = this.scaleX; - out.scaleY = this.scaleY; - out.translateX = this.translateX; - out.translateY = this.translateY; - out.alpha = this.alpha; - out.visibility = this.visibility; - out.willNotDraw = this.willNotDraw; - out.clipChildren = this.clipChildren; - out.elevation = this.elevation; - } - - /** - * Converts the data to the proto representation and returns the next property ref - * at the end of the iteration. - * @return - */ - public ViewPropertyRef toProto(ViewIdProvider idProvider, ArrayList classList, - ViewNode.Builder outBuilder) { - int classnameIndex = classList.indexOf(clazz); - if (classnameIndex < 0) { - classnameIndex = classList.size(); - classList.add(clazz); - } - outBuilder - .setClassnameIndex(classnameIndex) - .setHashcode(hashCode) - .setId(idProvider.getName(id)) - .setLeft(left) - .setTop(top) - .setWidth(right - left) - .setHeight(bottom - top) - .setTranslationX(translateX) - .setTranslationY(translateY) - .setScaleX(scaleX) - .setScaleY(scaleY) - .setAlpha(alpha) - .setVisibility(visibility) - .setWillNotDraw(willNotDraw) - .setElevation(elevation) - .setClipChildren(clipChildren); - - ViewPropertyRef result = next; - for (int i = 0; (i < childCount) && (result != null); i++) { - ViewNode.Builder childBuilder = ViewNode.newBuilder(); - result = result.toProto(idProvider, classList, childBuilder); - outBuilder.addChildren(childBuilder); - } - return result; - } - } - - private static class ViewRef implements Runnable { - public View view; - public int childCount = 0; - public ViewRef next; - - public Consumer callback = null; - public long creationTime = 0; - - public void transferTo(ViewPropertyRef out) { - out.childCount = this.childCount; - - View view = this.view; - this.view = null; - - out.clazz = view.getClass(); - out.hashCode = view.hashCode(); - out.id = view.getId(); - out.left = view.getLeft(); - out.top = view.getTop(); - out.right = view.getRight(); - out.bottom = view.getBottom(); - out.scrollX = view.getScrollX(); - out.scrollY = view.getScrollY(); - - out.translateX = view.getTranslationX(); - out.translateY = view.getTranslationY(); - out.scaleX = view.getScaleX(); - out.scaleY = view.getScaleY(); - out.alpha = view.getAlpha(); - out.elevation = view.getElevation(); - - out.visibility = view.getVisibility(); - out.willNotDraw = view.willNotDraw(); - } - - @Override - public void run() { - Consumer oldCallback = callback; - callback = null; - if (oldCallback != null) { - oldCallback.accept(this); - } - } - } - - private static final class ViewIdProvider { - - private final SparseArray mNames = new SparseArray<>(); - private final Resources mRes; - - ViewIdProvider(Resources res) { - mRes = res; - } - - String getName(int id) { - String name = mNames.get(id); - if (name == null) { - if (id >= 0) { - try { - name = mRes.getResourceTypeName(id) + '/' + mRes.getResourceEntryName(id); - } catch (Resources.NotFoundException e) { - name = "id/" + "0x" + Integer.toHexString(id).toUpperCase(); - } - } else { - name = "NO_ID"; - } - mNames.put(id, name); - } - return name; - } - } -} diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index 555fbb412b..76a91c0029 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -249,11 +249,11 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O /* widgetHandler= */ null, (ItemInfo) mWidgetView.getTag())); mLauncher - .getAppWidgetHost() - .startConfigActivity( - mLauncher, - mWidgetView.getAppWidgetId(), - Launcher.REQUEST_RECONFIGURE_APPWIDGET); + .getAppWidgetHolder() + .startConfigActivity( + mLauncher, + mWidgetView.getAppWidgetId(), + Launcher.REQUEST_RECONFIGURE_APPWIDGET); }); if (!hasSeenReconfigurableWidgetEducationTip()) { post(() -> { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 07d0f55321..7269d140a6 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -131,6 +131,7 @@ import com.android.launcher3.allapps.AllAppsRecyclerView; import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.BaseAllAppsContainerView; +import com.android.launcher3.allapps.BaseSearchConfig; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.compat.AccessibilityManagerCompat; @@ -204,7 +205,6 @@ import com.android.launcher3.views.FloatingIconView; import com.android.launcher3.views.FloatingSurfaceView; import com.android.launcher3.views.OptionsPopupView; import com.android.launcher3.views.ScrimView; -import com.android.launcher3.widget.LauncherAppWidgetHost; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; import com.android.launcher3.widget.PendingAddShortcutInfo; @@ -316,7 +316,7 @@ public class Launcher extends StatefulActivity DragLayer mDragLayer; private WidgetManagerHelper mAppWidgetManager; - private LauncherAppWidgetHost mAppWidgetHost; + private LauncherWidgetHolder mAppWidgetHolder; private final int[] mTmpAddItemCellCoordinates = new int[2]; @@ -395,6 +395,7 @@ public class Launcher extends StatefulActivity private LauncherState mPrevLauncherState; private StringCache mStringCache; + private BaseSearchConfig mBaseSearchConfig; @Override @TargetApi(Build.VERSION_CODES.S) @@ -480,8 +481,8 @@ public class Launcher extends StatefulActivity mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs); mAppWidgetManager = new WidgetManagerHelper(this); - mAppWidgetHost = createAppWidgetHost(); - mAppWidgetHost.startListening(); + mAppWidgetHolder = createAppWidgetHolder(); + mAppWidgetHolder.startListening(); setupViews(); crossFadeWithPreviousAppearance(); @@ -545,6 +546,9 @@ public class Launcher extends StatefulActivity getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING); } setTitle(R.string.home_screen); + + // TODO: move the SearchConfig to SearchState when new LauncherState is created. + mBaseSearchConfig = new BaseSearchConfig(); } protected LauncherOverlayManager getDefaultOverlay() { @@ -958,7 +962,7 @@ public class Launcher extends StatefulActivity AppWidgetHostView boundWidget = null; if (resultCode == RESULT_OK) { animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION; - final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId, + final AppWidgetHostView layout = mAppWidgetHolder.createView(this, appWidgetId, requestArgs.getWidgetHandler().getProviderInfo(this)); boundWidget = layout; onCompleteRunnable = new Runnable() { @@ -969,7 +973,7 @@ public class Launcher extends StatefulActivity } }; } else if (resultCode == RESULT_CANCELED) { - mAppWidgetHost.deleteAppWidgetId(appWidgetId); + mAppWidgetHolder.deleteAppWidgetId(appWidgetId); animationType = Workspace.CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION; } if (mDragLayer.getAnimatedView() != null) { @@ -992,7 +996,7 @@ public class Launcher extends StatefulActivity } hideKeyboard(); logStopAndResume(false /* isResume */); - mAppWidgetHost.setActivityStarted(false); + mAppWidgetHolder.setActivityStarted(false); NotificationListener.removeNotificationsChangedListener(getPopupDataProvider()); } @@ -1005,7 +1009,7 @@ public class Launcher extends StatefulActivity mOverlayManager.onActivityStarted(this); } - mAppWidgetHost.setActivityStarted(true); + mAppWidgetHolder.setActivityStarted(true); TraceHelper.INSTANCE.endSection(traceToken); } @@ -1025,7 +1029,7 @@ public class Launcher extends StatefulActivity NotificationListener.addNotificationsChangedListener(mPopupDataProvider); DiscoveryBounce.showForHomeIfNeeded(this); - mAppWidgetHost.setActivityResumed(true); + mAppWidgetHolder.setActivityResumed(true); } private void logStopAndResume(boolean isResume) { @@ -1140,7 +1144,7 @@ public class Launcher extends StatefulActivity @Override public void onStateSetEnd(LauncherState state) { super.onStateSetEnd(state); - getAppWidgetHost().setStateIsNormal(state == LauncherState.NORMAL); + getAppWidgetHolder().setStateIsNormal(state == LauncherState.NORMAL); getWorkspace().setClipChildren(!state.hasFlag(FLAG_MULTI_PAGE)); finishAutoCancelActionMode(); @@ -1205,7 +1209,7 @@ public class Launcher extends StatefulActivity if (!mDeferOverlayCallbacks) { mOverlayManager.onActivityPaused(this); } - mAppWidgetHost.setActivityResumed(false); + mAppWidgetHolder.setActivityResumed(false); } /** @@ -1430,7 +1434,7 @@ public class Launcher extends StatefulActivity if (hostView == null) { // Perform actual inflation because we're live - hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); + hostView = mAppWidgetHolder.createView(this, appWidgetId, appWidgetInfo); } LauncherAppWidgetInfo launcherInfo; @@ -1561,12 +1565,12 @@ public class Launcher extends StatefulActivity return mScrimView; } - public LauncherAppWidgetHost getAppWidgetHost() { - return mAppWidgetHost; + public LauncherWidgetHolder getAppWidgetHolder() { + return mAppWidgetHolder; } - protected LauncherAppWidgetHost createAppWidgetHost() { - return new LauncherAppWidgetHost(this, + protected LauncherWidgetHolder createAppWidgetHolder() { + return new LauncherWidgetHolder(this, appWidgetId -> getWorkspace().removeWidget(appWidgetId)); } @@ -1592,12 +1596,8 @@ public class Launcher extends StatefulActivity return mOldConfig.orientation; } - /** - * Whether keyboard sync is enabled for transitions between Home and All Apps. - * TODO(b/251387263): move this method inside an All Apps specific config class. - */ - public boolean isKeyboardSyncEnabled() { - return false; + public BaseSearchConfig getSearchConfig() { + return mBaseSearchConfig; } @Override @@ -1732,7 +1732,7 @@ public class Launcher extends StatefulActivity mRotationHelper.destroy(); try { - mAppWidgetHost.stopListening(); + mAppWidgetHolder.stopListening(); } catch (NullPointerException ex) { Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex); } @@ -1907,7 +1907,7 @@ public class Launcher extends StatefulActivity appWidgetId = CustomWidgetManager.INSTANCE.get(this).getWidgetIdForCustomProvider( info.componentName); } else { - appWidgetId = getAppWidgetHost().allocateAppWidgetId(); + appWidgetId = getAppWidgetHolder().allocateAppWidgetId(); } Bundle options = info.bindOptions; @@ -2021,7 +2021,7 @@ public class Launcher extends StatefulActivity final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo; mWorkspace.removeWorkspaceItem(v); if (deleteFromDb) { - getModelWriter().deleteWidgetInfo(widgetInfo, getAppWidgetHost(), reason); + getModelWriter().deleteWidgetInfo(widgetInfo, getAppWidgetHolder(), reason); } } else { return false; @@ -2279,7 +2279,7 @@ public class Launcher extends StatefulActivity mWorkspace.clearDropTargets(); mWorkspace.removeAllWorkspaceScreens(); - mAppWidgetHost.clearViews(); + mAppWidgetHolder.clearViews(); if (mHotseat != null) { mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout()); @@ -2586,7 +2586,7 @@ public class Launcher extends StatefulActivity if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) { // Id has not been allocated yet. Allocate a new id. - item.appWidgetId = mAppWidgetHost.allocateAppWidgetId(); + item.appWidgetId = mAppWidgetHolder.allocateAppWidgetId(); item.restoreStatus |= LauncherAppWidgetInfo.FLAG_ID_ALLOCATED; // Also try to bind the widget. If the bind fails, the user will be shown @@ -2648,18 +2648,18 @@ public class Launcher extends StatefulActivity // Verify that we own the widget if (appWidgetInfo == null) { FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId); - getModelWriter().deleteWidgetInfo(item, getAppWidgetHost(), removalReason); + getModelWriter().deleteWidgetInfo(item, getAppWidgetHolder(), removalReason); return null; } item.minSpanX = appWidgetInfo.minSpanX; item.minSpanY = appWidgetInfo.minSpanY; - view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo); + view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo); } else if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) && appWidgetInfo != null) { - mAppWidgetHost.addPendingView(item.appWidgetId, + mAppWidgetHolder.addPendingView(item.appWidgetId, new PendingAppWidgetHostView(this, item, mIconCache, false)); - view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo); + view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo); } else { view = new PendingAppWidgetHostView(this, item, mIconCache, false); } @@ -3017,7 +3017,8 @@ public class Launcher extends StatefulActivity writer.println(prefix + "\tmPendingRequestArgs=" + mPendingRequestArgs + " mPendingActivityResult=" + mPendingActivityResult); writer.println(prefix + "\tmRotationHelper: " + mRotationHelper); - writer.println(prefix + "\tmAppWidgetHost.isListening: " + mAppWidgetHost.isListening()); + writer.println(prefix + "\tmAppWidgetHolder.isListening: " + + mAppWidgetHolder.isListening()); // Extra logging for general debugging mDragLayer.dump(prefix, writer); diff --git a/src/com/android/launcher3/LauncherWidgetHolder.java b/src/com/android/launcher3/LauncherWidgetHolder.java new file mode 100644 index 0000000000..5fcd46fe4d --- /dev/null +++ b/src/com/android/launcher3/LauncherWidgetHolder.java @@ -0,0 +1,187 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3; + +import android.appwidget.AppWidgetHostView; +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.widget.LauncherAppWidgetHost; +import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; +import com.android.launcher3.widget.PendingAppWidgetHostView; + +import java.util.function.IntConsumer; + +/** + * A wrapper for LauncherAppWidgetHost. This class is created so the AppWidgetHost could run in + * background. + */ +public class LauncherWidgetHolder { + @NonNull + private final LauncherAppWidgetHost mWidgetHost; + + public LauncherWidgetHolder(@NonNull Context context) { + this(context, null); + } + + public LauncherWidgetHolder(@NonNull Context context, + @Nullable IntConsumer appWidgetRemovedCallback) { + mWidgetHost = new LauncherAppWidgetHost(context, appWidgetRemovedCallback); + } + + /** + * Starts listening to the widget updates from the server side + */ + public void startListening() { + mWidgetHost.startListening(); + } + + /** + * Set the STARTED state of the widget host + * @param isStarted True if setting the host as started, false otherwise + */ + public void setActivityStarted(boolean isStarted) { + mWidgetHost.setActivityStarted(isStarted); + } + + /** + * Set the RESUMED state of the widget host + * @param isResumed True if setting the host as resumed, false otherwise + */ + public void setActivityResumed(boolean isResumed) { + mWidgetHost.setActivityResumed(isResumed); + } + + /** + * Set the NORMAL state of the widget host + * @param isNormal True if setting the host to be in normal state, false otherwise + */ + public void setStateIsNormal(boolean isNormal) { + mWidgetHost.setStateIsNormal(isNormal); + } + + /** + * Delete the specified app widget from the host + * @param appWidgetId The ID of the app widget to be deleted + */ + public void deleteAppWidgetId(int appWidgetId) { + mWidgetHost.deleteAppWidgetId(appWidgetId); + } + + /** + * Add the pending view to the host for complete configuration in further steps + * @param appWidgetId The ID of the specified app widget + * @param view The {@link PendingAppWidgetHostView} of the app widget + */ + public void addPendingView(int appWidgetId, @NonNull PendingAppWidgetHostView view) { + mWidgetHost.addPendingView(appWidgetId, view); + } + + /** + * @return True if the host is listening to the widget updates, false otherwise + */ + public boolean isListening() { + return mWidgetHost.isListening(); + } + + /** + * @return The allocated app widget id if allocation is successful, returns -1 otherwise + */ + public int allocateAppWidgetId() { + return mWidgetHost.allocateAppWidgetId(); + } + + /** + * Add a listener that is triggered when the providers of the widgets are changed + * @param listener The listener that notifies when the providers changed + */ + public void addProviderChangeListener( + @NonNull LauncherAppWidgetHost.ProviderChangedListener listener) { + mWidgetHost.addProviderChangeListener(listener); + } + + /** + * Remove the specified listener from the host + * @param listener The listener that is to be removed from the host + */ + public void removeProviderChangeListener( + LauncherAppWidgetHost.ProviderChangedListener listener) { + mWidgetHost.removeProviderChangeListener(listener); + } + + /** + * Starts the configuration activity for the widget + * @param activity The activity in which to start the configuration page + * @param widgetId The ID of the widget + * @param requestCode The request code + */ + public void startConfigActivity(@NonNull BaseDraggingActivity activity, int widgetId, + int requestCode) { + mWidgetHost.startConfigActivity(activity, widgetId, requestCode); + } + + /** + * Starts the binding flow for the widget + * @param activity The activity for which to bind the widget + * @param appWidgetId The ID of the widget + * @param info The {@link AppWidgetProviderInfo} of the widget + * @param requestCode The request code + */ + public void startBindFlow(@NonNull BaseActivity activity, + int appWidgetId, @NonNull AppWidgetProviderInfo info, int requestCode) { + mWidgetHost.startBindFlow(activity, appWidgetId, info, requestCode); + } + + /** + * Stop the host from listening to the widget updates + */ + public void stopListening() { + mWidgetHost.stopListening(); + } + + /** + * Create a view for the specified app widget + * @param context The activity context for which the view is created + * @param appWidgetId The ID of the widget + * @param info The {@link LauncherAppWidgetProviderInfo} of the widget + * @return A view for the widget + */ + @NonNull + public AppWidgetHostView createView(@NonNull Context context, int appWidgetId, + @NonNull LauncherAppWidgetProviderInfo info) { + return mWidgetHost.createView(context, appWidgetId, info); + } + + /** + * Set the interaction handler for the widget host + * @param handler The interaction handler + */ + public void setInteractionHandler( + @Nullable LauncherAppWidgetHost.LauncherWidgetInteractionHandler handler) { + ApiWrapper.setHostInteractionHandler(mWidgetHost, handler); + } + + /** + * Clears all the views from the host + */ + public void clearViews() { + mWidgetHost.clearViews(); + } +} diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java index 0ee7aae088..791cfff9b0 100644 --- a/src/com/android/launcher3/SecondaryDropTarget.java +++ b/src/com/android/launcher3/SecondaryDropTarget.java @@ -288,7 +288,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList if (widgetId != INVALID_APPWIDGET_ID) { mLauncher.setWaitingForResult( PendingRequestArgs.forWidgetInfo(widgetId, null, info)); - mLauncher.getAppWidgetHost().startConfigActivity(mLauncher, widgetId, + mLauncher.getAppWidgetHolder().startConfigActivity(mLauncher, widgetId, REQUEST_RECONFIGURE_APPWIDGET); } return null; diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index fe8b3641e3..f834cce64f 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -109,7 +109,6 @@ import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.WallpaperOffsetInterpolator; -import com.android.launcher3.widget.LauncherAppWidgetHost; import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.NavigableAppWidgetHostView; @@ -3391,7 +3390,7 @@ public class Workspace extends PagedView public void widgetsRestored(final ArrayList changedInfo) { if (!changedInfo.isEmpty()) { DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo, - mLauncher.getAppWidgetHost()); + mLauncher.getAppWidgetHolder()); LauncherAppWidgetInfo item = changedInfo.get(0); final AppWidgetProviderInfo widgetInfo; @@ -3517,19 +3516,19 @@ public class Workspace extends PagedView */ private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener { private final ArrayList mInfos; - private final LauncherAppWidgetHost mHost; + private final LauncherWidgetHolder mWidgetHolder; private final Handler mHandler; private boolean mRefreshPending; DeferredWidgetRefresh(ArrayList infos, - LauncherAppWidgetHost host) { + LauncherWidgetHolder holder) { mInfos = infos; - mHost = host; + mWidgetHolder = holder; mHandler = mLauncher.mHandler; mRefreshPending = true; - mHost.addProviderChangeListener(this); + mWidgetHolder.addProviderChangeListener(this); // Force refresh after 10 seconds, if we don't get the provider changed event. // This could happen when the provider is no longer available in the app. Message msg = Message.obtain(mHandler, this); @@ -3539,7 +3538,7 @@ public class Workspace extends PagedView @Override public void run() { - mHost.removeProviderChangeListener(this); + mWidgetHolder.removeProviderChangeListener(this); mHandler.removeCallbacks(this); if (!mRefreshPending) { diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 624cfc2215..fa2c6e93c0 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -76,6 +76,8 @@ public class AllAppsTransitionController } }; + private static final float ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT = 0f; + public static final FloatProperty ALL_APPS_PULL_BACK_TRANSLATION = new FloatProperty("allAppsPullBackTranslation") { @@ -92,12 +94,18 @@ public class AllAppsTransitionController public void setValue(AllAppsTransitionController controller, float translation) { if (controller.mIsTablet) { controller.mAppsView.getActiveRecyclerView().setTranslationY(translation); + controller.getAppsViewPullbackTranslationY().setValue( + ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT); } else { controller.getAppsViewPullbackTranslationY().setValue(translation); + controller.mAppsView.getActiveRecyclerView().setTranslationY( + ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT); } } }; + private static final float ALL_APPS_PULL_BACK_ALPHA_DEFAULT = 1f; + public static final FloatProperty ALL_APPS_PULL_BACK_ALPHA = new FloatProperty("allAppsPullBackAlpha") { @@ -114,8 +122,12 @@ public class AllAppsTransitionController public void setValue(AllAppsTransitionController controller, float alpha) { if (controller.mIsTablet) { controller.mAppsView.getActiveRecyclerView().setAlpha(alpha); + controller.getAppsViewPullbackAlpha().setValue( + ALL_APPS_PULL_BACK_ALPHA_DEFAULT); } else { controller.getAppsViewPullbackAlpha().setValue(alpha); + controller.mAppsView.getActiveRecyclerView().setAlpha( + ALL_APPS_PULL_BACK_ALPHA_DEFAULT); } } }; @@ -226,14 +238,14 @@ public class AllAppsTransitionController StateAnimationConfig config, PendingAnimation builder) { if (mLauncher.isInState(ALL_APPS) && !ALL_APPS.equals(toState)) { // For atomic animations, we close the keyboard immediately. - if (!config.userControlled && !mLauncher.isKeyboardSyncEnabled()) { + if (!config.userControlled && !mLauncher.getSearchConfig().isKeyboardSyncEnabled()) { mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard(); } builder.addEndListener(success -> { // Reset pull back progress and alpha after switching states. - ALL_APPS_PULL_BACK_TRANSLATION.set(this, 0f); - ALL_APPS_PULL_BACK_ALPHA.set(this, 1f); + ALL_APPS_PULL_BACK_TRANSLATION.set(this, ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT); + ALL_APPS_PULL_BACK_ALPHA.set(this, ALL_APPS_PULL_BACK_ALPHA_DEFAULT); // We only want to close the keyboard if the animation has completed successfully. // The reason is that with keyboard sync, if the user swipes down from All Apps with diff --git a/src/com/android/launcher3/allapps/BaseSearchConfig.java b/src/com/android/launcher3/allapps/BaseSearchConfig.java new file mode 100644 index 0000000000..9f47e8d82f --- /dev/null +++ b/src/com/android/launcher3/allapps/BaseSearchConfig.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 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.allapps; + +/** Base config values for search. */ +public class BaseSearchConfig { + public BaseSearchConfig() {} + + /** + * Returns whether to enable the synchronized keyboard transition between Home and All Apps. + */ + public boolean isKeyboardSyncEnabled() { + return false; + } +} diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index 0a68d4aa34..514e7b22d8 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -36,6 +36,7 @@ import com.android.launcher3.LauncherProvider; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Settings; +import com.android.launcher3.LauncherWidgetHolder; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.FileLog; @@ -48,7 +49,6 @@ import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.Executors; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LooperExecutor; -import com.android.launcher3.widget.LauncherAppWidgetHost; import java.util.ArrayList; import java.util.Arrays; @@ -333,13 +333,13 @@ public class ModelWriter { /** * Deletes the widget info and the widget id. */ - public void deleteWidgetInfo(final LauncherAppWidgetInfo info, LauncherAppWidgetHost host, + public void deleteWidgetInfo(final LauncherAppWidgetInfo info, LauncherWidgetHolder holder, @Nullable final String reason) { notifyDelete(Collections.singleton(info)); - if (host != null && !info.isCustomWidget() && info.isWidgetIdAllocated()) { + if (holder != null && !info.isCustomWidget() && info.isWidgetIdAllocated()) { // Deleting an app widget ID is a void call but writes to disk before returning // to the caller... - enqueueDeleteRunnable(() -> host.deleteAppWidgetId(info.appWidgetId)); + enqueueDeleteRunnable(() -> holder.deleteAppWidgetId(info.appWidgetId)); } deleteItemFromDatabase(info, reason); } diff --git a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java index 93132664ef..9319a9c2c4 100644 --- a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java +++ b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java @@ -55,7 +55,7 @@ public class WidgetAddFlowHandler implements Parcelable { public void startBindFlow(Launcher launcher, int appWidgetId, ItemInfo info, int requestCode) { launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info)); - launcher.getAppWidgetHost() + launcher.getAppWidgetHolder() .startBindFlow(launcher, appWidgetId, mProviderInfo, requestCode); } @@ -77,7 +77,7 @@ public class WidgetAddFlowHandler implements Parcelable { return false; } launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info)); - launcher.getAppWidgetHost().startConfigActivity(launcher, appWidgetId, requestCode); + launcher.getAppWidgetHolder().startConfigActivity(launcher, appWidgetId, requestCode); return true; } diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java index 46141e0bc3..b18cd471cb 100644 --- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java +++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java @@ -59,7 +59,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { // Cleanup widget id if (mWidgetLoadingId != -1) { - mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); + mLauncher.getAppWidgetHolder().deleteAppWidgetId(mWidgetLoadingId); mWidgetLoadingId = -1; } @@ -69,7 +69,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { Log.d(TAG, "...removing widget from drag layer"); } mLauncher.getDragLayer().removeView(mInfo.boundWidget); - mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId()); + mLauncher.getAppWidgetHolder().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId()); mInfo.boundWidget = null; } } @@ -94,7 +94,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { mBindWidgetRunnable = new Runnable() { @Override public void run() { - mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); + mWidgetLoadingId = mLauncher.getAppWidgetHolder().allocateAppWidgetId(); if (LOGD) { Log.d(TAG, "Binding widget, id: " + mWidgetLoadingId); } @@ -116,7 +116,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { if (mWidgetLoadingId == -1) { return; } - AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView( + AppWidgetHostView hostView = mLauncher.getAppWidgetHolder().createView( (Context) mLauncher, mWidgetLoadingId, pInfo); mInfo.boundWidget = hostView; diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java index da8e25c1f6..21b2647d0c 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java @@ -321,7 +321,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mActivityContext.getAppWidgetHost().addProviderChangeListener(this); + mActivityContext.getAppWidgetHolder().addProviderChangeListener(this); notifyWidgetProvidersChanged(); onRecommendedWidgetsBound(); } @@ -329,7 +329,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mActivityContext.getAppWidgetHost().removeProviderChangeListener(this); + mActivityContext.getAppWidgetHolder().removeProviderChangeListener(this); mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView .removeOnAttachStateChangeListener(mBindScrollbarInSearchMode); if (mHasWorkProfile) { diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java index fa39ce0604..0f861eb1f3 100644 --- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java @@ -190,7 +190,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { waitForLauncherCondition("App widget options did not update", l -> appWidgetManager.getAppWidgetOptions(appWidgetId).getBoolean( WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED)); - executeOnLauncher(l -> l.getAppWidgetHost().startListening()); + executeOnLauncher(l -> l.getAppWidgetHolder().startListening()); verifyWidgetPresent(info); assertNull(mLauncher.getWorkspace().tryGetPendingWidget(100)); }