Fixing double state changes when using an InternalStateHandler
> Removing duplicate state handling on onCreate and onNewInetnt when InternalStateHandler is active
> Changing PinItemDragListener to use IntenalStateHandler
Change-Id: I42dcf82d1180c49430c6cf0b85d47072c4498ecc
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 1a8ae2a..34e3c4e 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -23,7 +23,6 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Build;
-import android.os.UserHandle;
import android.support.annotation.BinderThread;
import android.support.annotation.UiThread;
import android.util.FloatProperty;
@@ -32,6 +31,7 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
@@ -40,11 +40,7 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.states.InternalStateHandler;
-import com.android.launcher3.uioverrides.OverviewState;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.Task.TaskKey;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.concurrent.ExecutionException;
@@ -119,25 +115,10 @@
}
@Override
- public void onCreate(Launcher launcher) {
- mLauncher = launcher;
- mDragView = new SnapshotDragView(mLauncher, mTaskSnapshot);
- mLauncher.getDragLayer().addView(mDragView);
- mDragView.setPivotX(0);
- mDragView.setPivotY(0);
- mRecentsView = mLauncher.getOverviewPanel();
- mHotseat = mLauncher.getHotseat();
+ protected void init(Launcher launcher, boolean alreadyOnHome) {
+ AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
+ launcher.getStateManager().goToState(LauncherState.OVERVIEW, alreadyOnHome);
- // Optimization
- mLauncher.getAppsView().setVisibility(View.GONE);
-
- // Launch overview
- mRecentsView.update(consumeLastLoadPlan());
- mLauncher.getStateManager().goToState(LauncherState.OVERVIEW, false /* animate */);
- }
-
- @Override
- public void onNewIntent(Launcher launcher, boolean alreadyOnHome) {
mLauncher = launcher;
mDragView = new SnapshotDragView(mLauncher, mTaskSnapshot);
mLauncher.getDragLayer().addView(mDragView);
@@ -151,7 +132,6 @@
// Launch overview, animate if already on home
mRecentsView.update(consumeLastLoadPlan());
- mLauncher.getStateManager().goToState(LauncherState.OVERVIEW, alreadyOnHome);
}
/**
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index adaa785..a919f5e 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -17,8 +17,6 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
-import static com.android.launcher3.states.InternalStateHandler.EXTRA_STATE_HANDLER;
-
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.app.Service;
@@ -31,7 +29,6 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -42,7 +39,6 @@
import android.view.ViewConfiguration;
import android.view.WindowManager;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -212,13 +208,8 @@
RecentsTaskLoader loader = TouchInteractionService.getRecentsTaskLoader();
loadPlan.preloadPlan(loader, mRunningTask.id, UserHandle.myUserId());
- // Pass the
- Bundle extras = new Bundle();
- extras.putBinder(EXTRA_STATE_HANDLER, mInteractionHandler);
-
- // Start the activity
- Intent homeIntent = new Intent(mHomeIntent);
- homeIntent.putExtras(extras);
+ // Start the activity with our custom handler
+ Intent homeIntent = mInteractionHandler.addToIntent(new Intent(mHomeIntent));
startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle());
/*
ActivityManagerWrapper.getInstance().startRecentsActivity(null, options,
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2e93066..17eb55e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -107,7 +107,6 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
-import com.android.launcher3.dragndrop.PinItemDragListener;
import com.android.launcher3.dynamicui.WallpaperColorInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -359,9 +358,27 @@
mPopupDataProvider = new PopupDataProvider(this);
- restoreState(savedInstanceState);
+ mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation);
+ // In case we are on a device with locked rotation, we should look at preferences to check
+ // if the user has specifically allowed rotation.
+ if (!mRotationEnabled) {
+ mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext());
+ mRotationPrefChangeHandler = new RotationPrefChangeHandler();
+ mSharedPrefs.registerOnSharedPreferenceChangeListener(mRotationPrefChangeHandler);
+ }
- InternalStateHandler.handleCreate(this, getIntent());
+ boolean internalStateHandled = InternalStateHandler.handleCreate(this, getIntent());
+ if (internalStateHandled) {
+ // Temporarily enable the rotation
+ mRotationEnabled = true;
+
+ if (savedInstanceState != null) {
+ // InternalStateHandler has already set the appropriate state.
+ // We dont need to do anything.
+ savedInstanceState.remove(RUNTIME_STATE);
+ }
+ }
+ restoreState(savedInstanceState);
// We only load the page synchronously if the user rotates (or triggers a
// configuration change) while launcher is in the foreground
@@ -369,10 +386,13 @@
if (savedInstanceState != null) {
currentScreen = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, currentScreen);
}
+
if (!mModel.startLoader(currentScreen)) {
- // If we are not binding synchronously, show a fade in animation when
- // the first page bind completes.
- mDragLayer.setAlpha(0);
+ if (!internalStateHandled) {
+ // If we are not binding synchronously, show a fade in animation when
+ // the first page bind completes.
+ mDragLayer.setAlpha(0);
+ }
} else {
// Pages bound synchronously.
mWorkspace.setCurrentPage(currentScreen);
@@ -384,20 +404,6 @@
mDefaultKeySsb = new SpannableStringBuilder();
Selection.setSelection(mDefaultKeySsb, 0);
- mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation);
- // In case we are on a device with locked rotation, we should look at preferences to check
- // if the user has specifically allowed rotation.
- if (!mRotationEnabled) {
- mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext());
- mRotationPrefChangeHandler = new RotationPrefChangeHandler();
- mSharedPrefs.registerOnSharedPreferenceChangeListener(mRotationPrefChangeHandler);
- }
-
- if (PinItemDragListener.handleDragRequest(this, getIntent())) {
- // Temporarily enable the rotation
- mRotationEnabled = true;
- }
-
// On large interfaces, or on devices that a user has specifically enabled screen rotation,
// we want the screen to auto-rotate based on the current orientation
setRequestedOrientation(mRotationEnabled
@@ -1348,65 +1354,47 @@
boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(NORMAL)
&& AbstractFloatingView.getTopOpenView(this) == null;
boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
+ boolean internalStateHandled = InternalStateHandler
+ .handleNewIntent(this, intent, alreadyOnHome);
+
if (isActionMain) {
- if (mWorkspace == null) {
- // Can be cases where mWorkspace is null, this prevents a NPE
- return;
- }
+ if (!internalStateHandled) {
+ // Note: There should be at most one log per method call. This is enforced
+ // implicitly by using if-else statements.
+ UserEventDispatcher ued = getUserEventDispatcher();
+ AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(this);
+ if (topOpenView != null) {
+ topOpenView.logActionCommand(Action.Command.HOME_INTENT);
+ } else if (alreadyOnHome) {
+ Target target = newContainerTarget(mStateManager.getState().containerType);
+ target.pageIndex = mWorkspace.getCurrentPage();
+ ued.logActionCommand(Action.Command.HOME_INTENT, target);
+ }
- // Note: There should be at most one log per method call. This is enforced implicitly
- // by using if-else statements.
- UserEventDispatcher ued = getUserEventDispatcher();
- AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(this);
- if (topOpenView != null) {
- topOpenView.logActionCommand(Action.Command.HOME_INTENT);
- } else if (alreadyOnHome) {
- Target target = newContainerTarget(mStateManager.getState().containerType);
- target.pageIndex = mWorkspace.getCurrentPage();
- ued.logActionCommand(Action.Command.HOME_INTENT, target);
- }
+ // In all these cases, only animate if we're already on home
+ AbstractFloatingView.closeAllOpenViews(this, alreadyOnHome);
- // In all these cases, only animate if we're already on home
- AbstractFloatingView.closeAllOpenViews(this, alreadyOnHome);
- mStateManager.goToState(NORMAL, alreadyOnHome /* animated */);
+ mStateManager.goToState(NORMAL, alreadyOnHome /* animated */);
+
+ // Reset the apps view
+ if (!alreadyOnHome && mAppsView != null) {
+ mAppsView.reset();
+ }
+
+ if (shouldMoveToDefaultScreen && !mWorkspace.isTouchActive()) {
+ mWorkspace.post(mWorkspace::moveToDefaultScreen);
+ }
+ }
final View v = getWindow().peekDecorView();
if (v != null && v.getWindowToken() != null) {
UiThreadHelper.hideKeyboardAsync(this, v.getWindowToken());
}
- // Reset the apps view
- if (!alreadyOnHome && mAppsView != null) {
- mAppsView.reset();
- }
-
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onHomeIntent();
}
}
- PinItemDragListener.handleDragRequest(this, intent);
-
- if (mLauncherCallbacks != null) {
- mLauncherCallbacks.onNewIntent(intent);
- }
-
- // Defer moving to the default screen until after we callback to the LauncherCallbacks
- // as slow logic in the callbacks eat into the time the scroller expects for the snapToPage
- // animation.
- if (isActionMain) {
- if (shouldMoveToDefaultScreen && !mWorkspace.isTouchActive()) {
-
- mWorkspace.post(new Runnable() {
- @Override
- public void run() {
- if (mWorkspace != null) {
- mWorkspace.moveToDefaultScreen();
- }
- }
- });
- }
- }
- InternalStateHandler.handleNewIntent(this, intent, alreadyOnHome);
TraceHelper.endSection("NEW_INTENT");
}
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 78d753a..928258f 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -45,7 +45,6 @@
void onPause();
void onDestroy();
void onSaveInstanceState(Bundle outState);
- void onNewIntent(Intent intent);
void onActivityResult(int requestCode, int resultCode, Intent data);
void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults);
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index c843e72..db199c1 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -147,11 +147,12 @@
// Start home and pass the draw request params
PinItemDragListener listener = new PinItemDragListener(mRequest, bounds,
img.getBitmap().getWidth(), img.getWidth());
- Intent homeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setPackage(getPackageName())
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra(PinItemDragListener.EXTRA_PIN_ITEM_DRAG_LISTENER, listener);
+
+ Intent homeIntent = listener.addToIntent(
+ new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setPackage(getPackageName())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
if (!getResources().getBoolean(R.bool.allow_rotation) &&
!Utilities.isAllowRotationPrefEnabled(this) &&
diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
index 96aaee0..4629dad 100644
--- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
@@ -16,22 +16,25 @@
package com.android.launcher3.dragndrop;
+import static com.android.launcher3.LauncherState.NORMAL;
+
import android.content.ClipDescription;
import android.content.Intent;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
-import android.os.Parcel;
import android.os.SystemClock;
import android.util.Log;
import android.view.DragEvent;
import android.view.View;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.states.InternalStateHandler;
import com.android.launcher3.widget.PendingItemDragHelper;
import java.util.UUID;
@@ -39,7 +42,7 @@
/**
* {@link DragSource} for handling drop from a different window.
*/
-public abstract class BaseItemDragListener implements
+public abstract class BaseItemDragListener extends InternalStateHandler implements
View.OnDragListener, DragSource, DragOptions.PreDragCondition {
private static final String TAG = "BaseItemDragListener";
@@ -67,25 +70,16 @@
mId = UUID.randomUUID().toString();
}
- protected BaseItemDragListener(Parcel parcel) {
- mPreviewRect = Rect.CREATOR.createFromParcel(parcel);
- mPreviewBitmapWidth = parcel.readInt();
- mPreviewViewWidth = parcel.readInt();
- mId = parcel.readString();
- }
-
- protected void writeToParcel(Parcel parcel, int i) {
- mPreviewRect.writeToParcel(parcel, i);
- parcel.writeInt(mPreviewBitmapWidth);
- parcel.writeInt(mPreviewViewWidth);
- parcel.writeString(mId);
- }
-
public String getMimeType() {
return MIME_TYPE_PREFIX + mId;
}
- public void setLauncher(Launcher launcher) {
+ @Override
+ public void init(Launcher launcher, boolean alreadyOnHome) {
+ AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
+ launcher.getStateManager().goToState(NORMAL, alreadyOnHome /* animated */);
+ launcher.getDragLayer().setOnDragListener(this);
+
mLauncher = launcher;
mDragController = launcher.getDragController();
}
@@ -182,4 +176,7 @@
mLauncher.getDragLayer().setOnDragListener(null);
}
}
+
+ @Override
+ public void onLauncherResume() { }
}
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index b9d97ac..924bb4c 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -18,23 +18,18 @@
import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
-import android.content.Intent;
import android.content.pm.LauncherApps.PinItemRequest;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.view.DragEvent;
import android.view.View;
import android.widget.RemoteViews;
import com.android.launcher3.DragSource;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.PendingAddItemInfo;
-import com.android.launcher3.Utilities;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -46,9 +41,7 @@
* in the source window and is passed on to the Launcher activity as an Intent extra.
*/
@TargetApi(Build.VERSION_CODES.O)
-public class PinItemDragListener extends BaseItemDragListener implements Parcelable {
-
- public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener";
+public class PinItemDragListener extends BaseItemDragListener {
private final PinItemRequest mRequest;
@@ -58,22 +51,6 @@
mRequest = request;
}
- private PinItemDragListener(Parcel parcel) {
- super(parcel);
- mRequest = PinItemRequest.CREATOR.createFromParcel(parcel);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- super.writeToParcel(parcel, i);
- mRequest.writeToParcel(parcel, i);
- }
-
@Override
protected boolean onDragStart(DragEvent event) {
if (!mRequest.isValid()) {
@@ -126,33 +103,4 @@
}
return null;
}
-
- public static boolean handleDragRequest(Launcher launcher, Intent intent) {
- if (!Utilities.ATLEAST_OREO) {
- return false;
- }
- if (intent == null || !Intent.ACTION_MAIN.equals(intent.getAction())) {
- return false;
- }
- Parcelable dragExtra = intent.getParcelableExtra(EXTRA_PIN_ITEM_DRAG_LISTENER);
- if (dragExtra instanceof PinItemDragListener) {
- PinItemDragListener dragListener = (PinItemDragListener) dragExtra;
- dragListener.setLauncher(launcher);
-
- launcher.getDragLayer().setOnDragListener(dragListener);
- return true;
- }
- return false;
- }
-
- public static final Parcelable.Creator<PinItemDragListener> CREATOR =
- new Parcelable.Creator<PinItemDragListener>() {
- public PinItemDragListener createFromParcel(Parcel source) {
- return new PinItemDragListener(source);
- }
-
- public PinItemDragListener[] newArray(int size) {
- return new PinItemDragListener[size];
- }
- };
}
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index c6feefc..f084fd2 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -17,42 +17,52 @@
import android.content.Intent;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import com.android.launcher3.Launcher;
import com.android.launcher3.Launcher.OnResumeCallback;
/**
- * Utility class to sending state handling logic to Launcher from within the same process
+ * Utility class to sending state handling logic to Launcher from within the same process.
+ *
+ * Extending {@link Binder} ensures that the platform maintains a single instance of each object
+ * which allows this object to safely navigate the system process.
*/
public abstract class InternalStateHandler extends Binder implements OnResumeCallback {
public static final String EXTRA_STATE_HANDLER = "launcher.state_handler";
- public abstract void onCreate(Launcher launcher);
- public abstract void onNewIntent(Launcher launcher, boolean alreadyOnHome);
+ protected abstract void init(Launcher launcher, boolean alreadyOnHome);
- public static void handleCreate(Launcher launcher, Intent intent) {
- if (intent.getExtras() != null) {
- IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER);
- if (stateBinder instanceof InternalStateHandler) {
- InternalStateHandler handler = (InternalStateHandler) stateBinder;
- launcher.setOnResumeCallback(handler);
- handler.onCreate(launcher);
- }
- intent.getExtras().remove(EXTRA_STATE_HANDLER);
- }
+ public final Intent addToIntent(Intent intent) {
+ Bundle extras = new Bundle();
+ extras.putBinder(EXTRA_STATE_HANDLER, this);
+ intent.putExtras(extras);
+ return intent;
}
- public static void handleNewIntent(Launcher launcher, Intent intent, boolean alreadyOnHome) {
- if (intent.getExtras() != null) {
+ public static boolean handleCreate(Launcher launcher, Intent intent) {
+ return handleIntent(launcher, intent, false);
+ }
+
+ public static boolean handleNewIntent(Launcher launcher, Intent intent, boolean alreadyOnHome) {
+ return handleIntent(launcher, intent, alreadyOnHome);
+ }
+
+ private static boolean handleIntent(
+ Launcher launcher, Intent intent, boolean alreadyOnHome) {
+ boolean result = false;
+ if (intent != null && intent.getExtras() != null) {
IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER);
if (stateBinder instanceof InternalStateHandler) {
InternalStateHandler handler = (InternalStateHandler) stateBinder;
launcher.setOnResumeCallback(handler);
- handler.onNewIntent(launcher, alreadyOnHome);
+ handler.init(launcher, alreadyOnHome);
+ result = true;
}
intent.getExtras().remove(EXTRA_STATE_HANDLER);
}
+ return result;
}
}