Merge "Open taskMenu based on TaskIdAttributeContainer" into sc-v2-dev
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 6e2d2a9..38e8e72 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -301,7 +301,8 @@
         mActionsView = findViewById(R.id.overview_actions_view);
         RecentsView overviewPanel = (RecentsView) getOverviewPanel();
         SplitSelectStateController controller =
-                new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this));
+                new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this),
+                        getStateManager(), getDepthController());
         overviewPanel.init(mActionsView, controller);
         mActionsView.setDp(getDeviceProfile());
         mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 09a0b7d..d6efc71 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -128,7 +128,8 @@
         SYSUI_PROGRESS.set(getRootView().getSysUiScrim(), 0f);
 
         SplitSelectStateController controller =
-                new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this));
+                new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this),
+                        getStateManager(), null /*depthController*/);
         mDragLayer.recreateControllers();
         mFallbackRecentsView.init(mActionsView, controller);
 
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 6addfe3..142fafe 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -56,6 +56,7 @@
 import android.window.TransitionInfo;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
@@ -72,6 +73,7 @@
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskThumbnailView;
 import com.android.quickstep.views.TaskView;
@@ -149,10 +151,12 @@
         return taskView;
     }
 
-    public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
-            RemoteAnimationTargetCompat[] appTargets,
-            RemoteAnimationTargetCompat[] wallpaperTargets,
-            RemoteAnimationTargetCompat[] nonAppTargets, DepthController depthController,
+    public static void createRecentsWindowAnimator(
+            @NonNull TaskView v, boolean skipViewChanges,
+            @NonNull RemoteAnimationTargetCompat[] appTargets,
+            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
+            @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
+            @Nullable DepthController depthController,
             PendingAnimation out) {
         RecentsView recentsView = v.getRecentsView();
         boolean isQuickSwitch = v.isEndQuickswitchCuj();
@@ -418,15 +422,46 @@
         finishCallback.run();
     }
 
-    /** Legacy version (until shell transitions are enabled) */
-    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull Task initialTask,
+    /**
+     * Legacy version (until shell transitions are enabled)
+     *
+     * If {@param launchingTaskView} is not null, then this will play the tasks launch animation
+     * from the position of the GroupedTaskView (when user taps on the TaskView to start it).
+     * Technically this case should be taken care of by
+     * {@link #composeRecentsSplitLaunchAnimatorLegacy()} below, but the way we launch tasks whether
+     * it's a single task or multiple tasks results in different entry-points.
+     *
+     * If it is null, then it will simply fade in the starting apps and fade out launcher (for the
+     * case where launcher handles animating starting split tasks from app icon) */
+    public static void composeRecentsSplitLaunchAnimatorLegacy(
+            @Nullable GroupedTaskView launchingTaskView,
+            @NonNull Task initialTask,
             @NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets,
             @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
             @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
+            @NonNull StateManager stateManager,
+            @Nullable DepthController depthController,
             @NonNull Runnable finishCallback) {
+        if (launchingTaskView != null) {
+            AnimatorSet animatorSet = new AnimatorSet();
+            RecentsView recentsView = launchingTaskView.getRecentsView();
+            animatorSet.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    finishCallback.run();
+                }
+            });
+            composeRecentsLaunchAnimator(animatorSet, launchingTaskView,
+                    appTargets, wallpaperTargets, nonAppTargets,
+                    true, stateManager,
+                    recentsView, depthController);
+            animatorSet.start();
+            return;
+        }
+
         final ArrayList<SurfaceControl> openingTargets = new ArrayList<>();
         final ArrayList<SurfaceControl> closingTargets = new ArrayList<>();
-
         for (RemoteAnimationTargetCompat appTarget : appTargets) {
             final int taskId = appTarget.taskInfo != null ? appTarget.taskInfo.taskId : -1;
             final int mode = appTarget.mode;
@@ -490,7 +525,7 @@
             @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
             @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
             @NonNull StateManager stateManager, @NonNull RecentsView recentsView,
-            @NonNull DepthController depthController) {
+            @Nullable DepthController depthController) {
         boolean skipLauncherChanges = !launcherClosing;
 
         TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 9c6fd3d..8ccab71 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -162,7 +162,7 @@
      */
     public void setDeviceProfile(DeviceProfile deviceProfile) {
         boolean oldMultipleOrientationsSupported = isMultipleOrientationSupportedByDevice();
-        setFlag(FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY, !deviceProfile.allowRotation);
+        setFlag(FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY, !deviceProfile.isTablet);
         if (mListenersInitialized) {
             boolean newMultipleOrientationsSupported = isMultipleOrientationSupportedByDevice();
             // If isMultipleOrientationSupportedByDevice is changed, init or destroy listeners
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 41aaa1a..c784d82 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -30,11 +30,18 @@
 import android.view.SurfaceControl;
 import android.window.TransitionInfo;
 
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.views.GroupedTaskView;
+import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@@ -52,23 +59,32 @@
 
     private final Handler mHandler;
     private final SystemUiProxy mSystemUiProxy;
+    private final StateManager mStateManager;
+    private final DepthController mDepthController;
     private @StagePosition int mStagePosition;
     private Task mInitialTask;
     private Task mSecondTask;
     private Rect mInitialBounds;
     private boolean mRecentsAnimationRunning;
+    /** If not null, this is the TaskView we want to launch from */
+    @Nullable
+    private GroupedTaskView mLaunchingTaskView;
 
-    public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
+    public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy,
+            StateManager stateManager,
+            DepthController depthController) {
         mHandler = handler;
         mSystemUiProxy = systemUiProxy;
+        mStateManager = stateManager;
+        mDepthController = depthController;
     }
 
     /**
      * To be called after first task selected
      */
-    public void setInitialTaskSelect(Task taskView, @StagePosition int stagePosition,
+    public void setInitialTaskSelect(Task task, @StagePosition int stagePosition,
             Rect initialBounds) {
-        mInitialTask = taskView;
+        mInitialTask = task;
         mStagePosition = stagePosition;
         mInitialBounds = initialBounds;
     }
@@ -76,13 +92,25 @@
     /**
      * To be called after second task selected
      */
-    public void setSecondTaskId(Task taskView, Consumer<Boolean> callback) {
-        mSecondTask = taskView;
+    public void setSecondTaskId(Task task, Consumer<Boolean> callback) {
+        mSecondTask = task;
         launchTasks(mInitialTask, mSecondTask, mStagePosition, callback,
                 false /* freezeTaskList */);
     }
 
     /**
+     * To be called when we want to launch split pairs from an existing GroupedTaskView.
+     */
+    public void launchTasks(GroupedTaskView groupedTaskView,
+            Consumer<Boolean> callback, boolean freezeTaskList) {
+        mLaunchingTaskView = groupedTaskView;
+        TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers =
+                groupedTaskView.getTaskIdAttributeContainers();
+        launchTasks(taskIdAttributeContainers[0].getTask(), taskIdAttributeContainers[1].getTask(),
+                taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList);
+    }
+
+    /**
      * @param stagePosition representing location of task1
      */
     public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition,
@@ -169,8 +197,9 @@
                 RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
                 Runnable finishedCallback) {
             postAsyncCallback(mHandler,
-                    () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask,
-                            mSecondTask, apps, wallpapers, nonApps, () -> {
+                    () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(
+                            mLaunchingTaskView, mInitialTask, mSecondTask, apps, wallpapers,
+                            nonApps, mStateManager, mDepthController, () -> {
                                 finishedCallback.run();
                                 if (mSuccessCallback != null) {
                                     mSuccessCallback.accept(true);
@@ -201,6 +230,7 @@
         mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
         mInitialBounds = null;
         mRecentsAnimationRunning = false;
+        mLaunchingTaskView = null;
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index c26837c..325ec04 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -73,6 +73,32 @@
         mSplitPlaceholderView.setAlpha(0);
     }
 
+    private void init(StatefulActivity launcher, TaskView originalView, RectF positionOut) {
+        mStartingPosition = positionOut;
+        updateInitialPositionForView(originalView);
+        final InsettableFrameLayout.LayoutParams lp =
+                (InsettableFrameLayout.LayoutParams) getLayoutParams();
+
+        mSplitPlaceholderView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
+        positionOut.round(mOutline);
+        setPivotX(0);
+        setPivotY(0);
+
+        // Copy bounds of exiting thumbnail into ImageView
+        TaskThumbnailView thumbnail = originalView.getThumbnail();
+        mImageView.setImageBitmap(thumbnail.getThumbnail());
+        mImageView.setVisibility(VISIBLE);
+
+        mOrientationHandler = originalView.getRecentsView().getPagedOrientationHandler();
+        mSplitPlaceholderView.setIconView(originalView.getIconView(),
+                launcher.getDeviceProfile().overviewTaskIconDrawableSizePx);
+        mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated());
+    }
+
+    /**
+     * Configures and returns a an instance of {@link FloatingTaskView} initially matching the
+     * appearance of {@code originalView}.
+     */
     public static FloatingTaskView getFloatingTaskView(StatefulActivity launcher,
             TaskView originalView, RectF positionOut) {
         final BaseDragLayer dragLayer = launcher.getDragLayer();
@@ -80,28 +106,7 @@
         final FloatingTaskView floatingView = (FloatingTaskView) launcher.getLayoutInflater()
                 .inflate(R.layout.floating_split_select_view, parent, false);
 
-        floatingView.mStartingPosition = positionOut;
-        floatingView.updateInitialPositionForView(originalView);
-        final InsettableFrameLayout.LayoutParams lp =
-                (InsettableFrameLayout.LayoutParams) floatingView.getLayoutParams();
-
-        floatingView.mSplitPlaceholderView.setLayoutParams(
-                new FrameLayout.LayoutParams(lp.width, lp.height));
-        positionOut.round(floatingView.mOutline);
-        floatingView.setPivotX(0);
-        floatingView.setPivotY(0);
-
-        // Copy bounds of exiting thumbnail into ImageView
-        TaskThumbnailView thumbnail = originalView.getThumbnail();
-        floatingView.mImageView.setImageBitmap(thumbnail.getThumbnail());
-        floatingView.mImageView.setVisibility(VISIBLE);
-
-        floatingView.mOrientationHandler =
-                originalView.getRecentsView().getPagedOrientationHandler();
-        floatingView.mSplitPlaceholderView.setIconView(originalView.getIconView(),
-                launcher.getDeviceProfile().overviewTaskIconDrawableSizePx);
-        floatingView.mSplitPlaceholderView.getIconView()
-                .setRotation(floatingView.mOrientationHandler.getDegreesRotated());
+        floatingView.init(launcher, originalView, positionOut);
         parent.addView(floatingView);
         return floatingView;
     }
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 05bf0f5..4771d1e 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -148,8 +148,8 @@
     @Nullable
     @Override
     public RunnableList launchTaskAnimated() {
-        getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
-                STAGE_POSITION_TOP_OR_LEFT, null /*callback*/,
+        getRecentsView().getSplitPlaceholder().launchTasks(this /*groupedTaskView*/,
+                null /*callback*/,
                 false /* freezeTaskList */);
         return null;
     }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index e64ea90..f2836ca 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -16,13 +16,10 @@
 
 package com.android.launcher3;
 
-import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
-
 import static com.android.launcher3.ResourceUtils.pxFromDp;
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.Utilities.pxFromSp;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
-import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -64,7 +61,6 @@
     public final boolean isPhone;
     public final boolean transposeLayoutWithOrientation;
     public final boolean isTwoPanels;
-    public final boolean allowRotation;
 
     // Device properties in current orientation
     public final boolean isLandscape;
@@ -244,12 +240,7 @@
         availableHeightPx = windowBounds.availableSize.y;
 
         mInfo = info;
-        // If the device's pixel density was scaled (usually via settings for A11y), use the
-        // original dimensions to determine if rotation is allowed of not.
-        float originalSmallestWidth = dpiFromPx(Math.min(widthPx, heightPx), DENSITY_DEVICE_STABLE);
-        allowRotation = originalSmallestWidth >= MIN_TABLET_WIDTH;
-        // Tablet UI does not support emulated landscape.
-        isTablet = allowRotation && info.isTablet(windowBounds);
+        isTablet = info.isTablet(windowBounds);
         isPhone = !isTablet;
         isTwoPanels = isTablet && useTwoPanels;
 
@@ -1031,7 +1022,6 @@
         writer.println(prefix + "DeviceProfile:");
         writer.println(prefix + "\t1 dp = " + mMetrics.density + " px");
 
-        writer.println(prefix + "\tallowRotation:" + allowRotation);
         writer.println(prefix + "\tisTablet:" + isTablet);
         writer.println(prefix + "\tisPhone:" + isPhone);
         writer.println(prefix + "\ttransposeLayoutWithOrientation:"
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index f348a33..0c39632 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -49,6 +49,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.states.RotationHelper;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 
 import java.util.Collections;
@@ -253,12 +254,13 @@
                 case ALLOW_ROTATION_PREFERENCE_KEY:
                     DeviceProfile deviceProfile = InvariantDeviceProfile.INSTANCE.get(
                             getContext()).getDeviceProfile(getContext());
-                    if (deviceProfile.allowRotation) {
+                    if (deviceProfile.isTablet) {
                         // Launcher supports rotation by default. No need to show this setting.
                         return false;
                     }
                     // Initialize the UI once
-                    preference.setDefaultValue(false);
+                    preference.setDefaultValue(
+                            RotationHelper.getAllowRotationDefaultValue(deviceProfile));
                     return true;
 
                 case FLAGS_PREFERENCE_KEY:
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 87871b1..867fd99 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -18,6 +18,10 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
+
+import static com.android.launcher3.Utilities.dpiFromPx;
+import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
 
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@@ -25,7 +29,6 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.util.ActivityTracker;
 import com.android.launcher3.util.UiThreadHelper;
 
 /**
@@ -38,6 +41,17 @@
 
     public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
 
+    /**
+     * Returns the default value of {@link #ALLOW_ROTATION_PREFERENCE_KEY} preference.
+     */
+    public static boolean getAllowRotationDefaultValue(DeviceProfile deviceProfile) {
+        // If the device's pixel density was scaled (usually via settings for A11y), use the
+        // original dimensions to determine if rotation is allowed of not.
+        float originalSmallestWidth = dpiFromPx(
+                Math.min(deviceProfile.widthPx, deviceProfile.heightPx), DENSITY_DEVICE_STABLE);
+        return originalSmallestWidth >= MIN_TABLET_WIDTH;
+    }
+
     public static final int REQUEST_NONE = 0;
     public static final int REQUEST_ROTATE = 1;
     public static final int REQUEST_LOCK = 2;
@@ -51,7 +65,7 @@
 
     /**
      * Rotation request made by
-     * {@link ActivityTracker.SchedulerCallback}.
+     * {@link com.android.launcher3.util.ActivityTracker.SchedulerCallback}.
      * This supersedes any other request.
      */
     private int mStateHandlerRequest = REQUEST_NONE;
@@ -84,7 +98,7 @@
                 mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
             }
             mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
-                    mActivity.getDeviceProfile().allowRotation);
+                    getAllowRotationDefaultValue(mActivity.getDeviceProfile()));
         } else {
             if (mSharedPrefs != null) {
                 mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
@@ -98,7 +112,7 @@
         if (mDestroyed) return;
         boolean wasRotationEnabled = mHomeRotationEnabled;
         mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
-                mActivity.getDeviceProfile().allowRotation);
+                getAllowRotationDefaultValue(mActivity.getDeviceProfile()));
         if (mHomeRotationEnabled != wasRotationEnabled) {
             notifyChange();
         }
@@ -106,7 +120,7 @@
 
     @Override
     public void onDeviceProfileChanged(DeviceProfile dp) {
-        boolean ignoreAutoRotateSettings = dp.allowRotation;
+        boolean ignoreAutoRotateSettings = dp.isTablet;
         if (mIgnoreAutoRotateSettings != ignoreAutoRotateSettings) {
             setIgnoreAutoRotateSettings(ignoreAutoRotateSettings);
             notifyChange();
@@ -143,7 +157,7 @@
     public void initialize() {
         if (!mInitialized) {
             mInitialized = true;
-            setIgnoreAutoRotateSettings(mActivity.getDeviceProfile().allowRotation);
+            setIgnoreAutoRotateSettings(mActivity.getDeviceProfile().isTablet);
             mActivity.addOnDeviceProfileChangeListener(this);
             notifyChange();
         }