diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java index 0a0f9adb82..6cb803a12c 100644 --- a/src/com/android/launcher3/DropTarget.java +++ b/src/com/android/launcher3/DropTarget.java @@ -25,6 +25,8 @@ import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.folder.FolderNameProvider; +import com.android.launcher3.logging.InstanceId; +import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.model.data.ItemInfo; /** @@ -75,6 +77,11 @@ public interface DropTarget { * DragView represents. May be an actual View class or a virtual stand-in */ public DraggableView originalView = null; + /** Used for matching DROP event with its corresponding DRAG event on the server side. */ + final InstanceId mLogInstanceId = + new InstanceIdSequence(1 << 20 /*InstanceId.INSTANCE_ID_MAX*/) + .newInstanceId(); + public DragObject(Context context) { if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) { folderNameProvider = FolderNameProvider.newInstance(context); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index a58bf70954..dd00bd302d 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -416,7 +416,7 @@ public class Workspace extends PagedView mLauncher.getStateManager().goToState(SPRING_LOADED); mStatsLogManager.log( LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED, - dragObject.originalDragInfo.id, + dragObject.mLogInstanceId, dragObject.originalDragInfo.buildProto(null)); } @@ -1892,7 +1892,7 @@ public class Workspace extends PagedView } mStatsLogManager.log( LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED, - d.dragInfo.id, + d.mLogInstanceId, d.dragInfo.buildProto(null)); } diff --git a/src/com/android/launcher3/logging/InstanceId.java b/src/com/android/launcher3/logging/InstanceId.java new file mode 100644 index 0000000000..e720d758b4 --- /dev/null +++ b/src/com/android/launcher3/logging/InstanceId.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2020 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.logging; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + + +/** + * An opaque identifier used to disambiguate which logs refer to a particular instance of some + * UI element. Useful when there might be multiple instances simultaneously active. + * Obtain from InstanceIdSequence. Clipped to range [0, INSTANCE_ID_MAX]. + * + * Copy of frameworks/base/core/java/com/android/internal/logging/InstanceId.java. + */ +public final class InstanceId implements Parcelable { + // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values + static final int INSTANCE_ID_MAX = 1 << 20; + + private final int mId; + InstanceId(int id) { + mId = min(max(0, id), INSTANCE_ID_MAX); + } + + private InstanceId(Parcel in) { + this(in.readInt()); + } + + @VisibleForTesting + public int getId() { + return mId; + } + + @NonNull + @Override + public String toString() { + return mId + ""; + } + + /** + * Create a fake instance ID for testing purposes. Not for production use. See also + * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence. + * @param id The ID you want to assign. + * @return new InstanceId. + */ + @VisibleForTesting + public static InstanceId fakeInstanceId(int id) { + return new InstanceId(id); + } + + @Override + public int hashCode() { + return mId; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof InstanceId)) { + return false; + } + return mId == ((InstanceId) obj).mId; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mId); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public InstanceId createFromParcel(Parcel in) { + return new InstanceId(in); + } + + @Override + public InstanceId[] newArray(int size) { + return new InstanceId[size]; + } + }; + +} diff --git a/src/com/android/launcher3/logging/InstanceIdSequence.java b/src/com/android/launcher3/logging/InstanceIdSequence.java new file mode 100644 index 0000000000..a4b795352a --- /dev/null +++ b/src/com/android/launcher3/logging/InstanceIdSequence.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 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.logging; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +import androidx.annotation.VisibleForTesting; + +import java.security.SecureRandom; +import java.util.Random; + +/** + * Generates random InstanceIds in range [1, instanceIdMax] for passing to + * UiEventLogger.logWithInstanceId(). Holds a SecureRandom, which self-seeds on first use; try to + * give it a long lifetime. Safe for concurrent use. + * + * Copy of frameworks/base/core/java/com/android/internal/logging/InstanceIdSequence.java + */ +public class InstanceIdSequence { + protected final int mInstanceIdMax; + private final Random mRandom = new SecureRandom(); + + /** + * Constructs a sequence with identifiers [1, instanceIdMax]. Capped at INSTANCE_ID_MAX. + * @param instanceIdMax Limiting value of identifiers. Normally positive: otherwise you get + * an all-1 sequence. + */ + public InstanceIdSequence(int instanceIdMax) { + mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX); + } + + /** + * Gets the next instance from the sequence. Safe for concurrent use. + * @return new InstanceId + */ + public InstanceId newInstanceId() { + return newInstanceIdInternal(1 + mRandom.nextInt(mInstanceIdMax)); + } + + /** + * Factory function for instance IDs, used for testing. + * @param id + * @return new InstanceId(id) + */ + @VisibleForTesting + protected InstanceId newInstanceIdInternal(int id) { + return new InstanceId(id); + } +} diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 1e2ce53beb..62a3829d04 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -87,7 +87,7 @@ public class StatsLogManager implements ResourceBasedOverride { /** * Logs an event and accompanying {@link ItemInfo} */ - public void log(LauncherEvent event, int instanceId, LauncherAtom.ItemInfo itemInfo) { + public void log(LauncherEvent event, InstanceId instanceId, LauncherAtom.ItemInfo itemInfo) { Log.d(TAG, String.format("%s(InstanceId:%s)\n%s", event.name(), instanceId, itemInfo)); // Call StatsLog method }