Merge "Intercept touch events from anywhere while all apps is closing" into ub-launcher3-master
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
index 8f4ce43..605774d 100644
--- a/quickstep/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -25,8 +25,6 @@
<string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
- <string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
-
<string name="model_delegate_class" translatable="false">com.android.launcher3.model.QuickstepModelDelegate</string>
</resources>
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index e9fc423..d8064a2 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -569,6 +569,7 @@
pw.println(" isUserUnlocked=" + mIsUserUnlocked);
pw.println(" isOneHandedModeEnabled=" + mIsOneHandedModeEnabled);
pw.println(" isSwipeToNotificationEnabled=" + mIsSwipeToNotificationEnabled);
+ pw.println(" deferredGestureRegion=" + mDeferredGestureRegion);
mRotationTouchHelper.dump(pw);
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 5b4a239..ebdc867 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -64,8 +64,8 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.tracing.nano.LauncherTraceProto;
-import com.android.launcher3.tracing.nano.TouchInteractionServiceProto;
+import com.android.launcher3.tracing.LauncherTraceProto;
+import com.android.launcher3.tracing.TouchInteractionServiceProto;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TraceHelper;
@@ -105,7 +105,7 @@
*/
@TargetApi(Build.VERSION_CODES.R)
public class TouchInteractionService extends Service implements PluginListener<OverscrollPlugin>,
- ProtoTraceable<LauncherTraceProto> {
+ ProtoTraceable<LauncherTraceProto.Builder> {
private static final String TAG = "TouchInteractionService";
@@ -368,9 +368,12 @@
// Update the tracing state
if ((mDeviceState.getSystemUiStateFlags() & SYSUI_STATE_TRACING_ENABLED) != 0) {
- ProtoTracer.INSTANCE.get(TouchInteractionService.this).start();
+ Log.d(TAG, "Starting tracing.");
+ ProtoTracer.INSTANCE.get(this).start();
} else {
- ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
+ Log.d(TAG, "Stopping tracing. Dumping to file="
+ + ProtoTracer.INSTANCE.get(this).getTraceFile());
+ ProtoTracer.INSTANCE.get(this).stop();
}
}
}
@@ -394,7 +397,7 @@
disposeEventHandlers();
mDeviceState.destroy();
SystemUiProxy.INSTANCE.get(this).setProxy(null);
- ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
+ ProtoTracer.INSTANCE.get(this).stop();
ProtoTracer.INSTANCE.get(this).remove(this);
getSystemService(AccessibilityManager.class)
@@ -503,6 +506,7 @@
reset();
}
TraceHelper.INSTANCE.endFlagsOverride(traceToken);
+ ProtoTracer.INSTANCE.get(this).scheduleFrameUpdate();
}
private GestureState createGestureState(GestureState previousGestureState) {
@@ -821,8 +825,7 @@
pw.println(" mConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
pw.println("ProtoTrace:");
- pw.println(" file="
- + ProtoTracer.INSTANCE.get(TouchInteractionService.this).getTraceFile());
+ pw.println(" file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
}
}
@@ -878,11 +881,10 @@
}
@Override
- public void writeToProto(LauncherTraceProto proto) {
- if (proto.touchInteractionService == null) {
- proto.touchInteractionService = new TouchInteractionServiceProto();
- }
- proto.touchInteractionService.serviceConnected = true;
- proto.touchInteractionService.serviceConnected = true;
+ public void writeToProto(LauncherTraceProto.Builder proto) {
+ TouchInteractionServiceProto.Builder serviceProto =
+ TouchInteractionServiceProto.newBuilder();
+ serviceProto.setServiceConnected(true);
+ proto.setTouchInteractionService(serviceProto);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/ProtoTracer.java b/quickstep/src/com/android/quickstep/util/ProtoTracer.java
index 190763a..ef9586d 100644
--- a/quickstep/src/com/android/quickstep/util/ProtoTracer.java
+++ b/quickstep/src/com/android/quickstep/util/ProtoTracer.java
@@ -16,24 +16,23 @@
package com.android.quickstep.util;
-import static com.android.launcher3.tracing.nano.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_H;
-import static com.android.launcher3.tracing.nano.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_L;
+import static com.android.launcher3.tracing.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_H_VALUE;
+import static com.android.launcher3.tracing.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_L_VALUE;
import android.content.Context;
import android.os.SystemClock;
-import com.android.launcher3.tracing.nano.LauncherTraceProto;
-import com.android.launcher3.tracing.nano.LauncherTraceEntryProto;
-import com.android.launcher3.tracing.nano.LauncherTraceFileProto;
+import android.os.Trace;
+import com.android.launcher3.tracing.LauncherTraceProto;
+import com.android.launcher3.tracing.LauncherTraceEntryProto;
+import com.android.launcher3.tracing.LauncherTraceFileProto;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.shared.tracing.FrameProtoTracer;
import com.android.systemui.shared.tracing.FrameProtoTracer.ProtoTraceParams;
import com.android.systemui.shared.tracing.ProtoTraceable;
-import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.MessageLite;
import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Queue;
@@ -41,18 +40,20 @@
/**
* Controller for coordinating winscope proto tracing.
*/
-public class ProtoTracer implements ProtoTraceParams<MessageNano,
- LauncherTraceFileProto, LauncherTraceEntryProto, LauncherTraceProto> {
+public class ProtoTracer implements ProtoTraceParams<MessageLite.Builder,
+ LauncherTraceFileProto.Builder, LauncherTraceEntryProto.Builder,
+ LauncherTraceProto.Builder> {
public static final MainThreadInitializedObject<ProtoTracer> INSTANCE =
new MainThreadInitializedObject<>(ProtoTracer::new);
private static final String TAG = "ProtoTracer";
- private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+ private static final long MAGIC_NUMBER_VALUE =
+ ((long) MAGIC_NUMBER_H_VALUE << 32) | MAGIC_NUMBER_L_VALUE;
private final Context mContext;
- private final FrameProtoTracer<MessageNano,
- LauncherTraceFileProto, LauncherTraceEntryProto, LauncherTraceProto> mProtoTracer;
+ private final FrameProtoTracer<MessageLite.Builder, LauncherTraceFileProto.Builder,
+ LauncherTraceEntryProto.Builder, LauncherTraceProto.Builder> mProtoTracer;
public ProtoTracer(Context context) {
mContext = context;
@@ -65,40 +66,47 @@
}
@Override
- public LauncherTraceFileProto getEncapsulatingTraceProto() {
- return new LauncherTraceFileProto();
+ public LauncherTraceFileProto.Builder getEncapsulatingTraceProto() {
+ return LauncherTraceFileProto.newBuilder();
}
@Override
- public LauncherTraceEntryProto updateBufferProto(LauncherTraceEntryProto reuseObj,
- ArrayList<ProtoTraceable<LauncherTraceProto>> traceables) {
- LauncherTraceEntryProto proto = reuseObj != null
- ? reuseObj
- : new LauncherTraceEntryProto();
- proto.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
- proto.launcher = proto.launcher != null ? proto.launcher : new LauncherTraceProto();
+ public LauncherTraceEntryProto.Builder updateBufferProto(
+ LauncherTraceEntryProto.Builder reuseObj,
+ ArrayList<ProtoTraceable<LauncherTraceProto.Builder>> traceables) {
+ Trace.beginSection("ProtoTracer.updateBufferProto");
+ LauncherTraceEntryProto.Builder proto = LauncherTraceEntryProto.newBuilder();
+ proto.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+ LauncherTraceProto.Builder launcherProto = LauncherTraceProto.newBuilder();
for (ProtoTraceable t : traceables) {
- t.writeToProto(proto.launcher);
+ t.writeToProto(launcherProto);
}
+ proto.setLauncher(launcherProto);
+ Trace.endSection();
return proto;
}
@Override
- public byte[] serializeEncapsulatingProto(LauncherTraceFileProto encapsulatingProto,
- Queue<LauncherTraceEntryProto> buffer) {
- encapsulatingProto.magicNumber = MAGIC_NUMBER_VALUE;
- encapsulatingProto.entry = buffer.toArray(new LauncherTraceEntryProto[0]);
- return MessageNano.toByteArray(encapsulatingProto);
+ public byte[] serializeEncapsulatingProto(LauncherTraceFileProto.Builder encapsulatingProto,
+ Queue<LauncherTraceEntryProto.Builder> buffer) {
+ Trace.beginSection("ProtoTracer.serializeEncapsulatingProto");
+ encapsulatingProto.setMagicNumber(MAGIC_NUMBER_VALUE);
+ for (LauncherTraceEntryProto.Builder entry : buffer) {
+ encapsulatingProto.addEntry(entry);
+ }
+ byte[] bytes = encapsulatingProto.build().toByteArray();
+ Trace.endSection();
+ return bytes;
}
@Override
- public byte[] getProtoBytes(MessageNano proto) {
- return MessageNano.toByteArray(proto);
+ public byte[] getProtoBytes(MessageLite.Builder proto) {
+ return proto.build().toByteArray();
}
@Override
- public int getProtoSize(MessageNano proto) {
- return proto.getCachedSize();
+ public int getProtoSize(MessageLite.Builder proto) {
+ return proto.build().getSerializedSize();
}
public void start() {
@@ -109,11 +117,11 @@
mProtoTracer.stop();
}
- public void add(ProtoTraceable<LauncherTraceProto> traceable) {
+ public void add(ProtoTraceable<LauncherTraceProto.Builder> traceable) {
mProtoTracer.add(traceable);
}
- public void remove(ProtoTraceable<LauncherTraceProto> traceable) {
+ public void remove(ProtoTraceable<LauncherTraceProto.Builder> traceable) {
mProtoTracer.remove(traceable);
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 982a7c4..6ae91b6 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -79,7 +79,6 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
@@ -706,12 +705,9 @@
super.onTouchEvent(ev);
TaskView taskView = getCurrentPageTaskView();
- if (taskView != null) {
- TouchDelegate mChildTouchDelegate = taskView.getIconTouchDelegate(ev);
- if (mChildTouchDelegate != null && mChildTouchDelegate.onTouchEvent(ev)) {
- // Keep consuming events to pass to delegate
- return true;
- }
+ if (taskView != null && taskView.offerTouchToChildren(ev)) {
+ // Keep consuming events to pass to delegate
+ return true;
}
final int x = (int) ev.getX();
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 259cd4d..321821b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -135,6 +135,7 @@
* delegated bounds only to be updated.
*/
private TransformingTouchDelegate mIconTouchDelegate;
+ private TransformingTouchDelegate mChipTouchDelegate;
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
Collections.singletonList(new Rect());
@@ -200,6 +201,7 @@
private View mContextualChipWrapper;
private View mContextualChip;
private final float[] mIconCenterCoords = new float[2];
+ private final float[] mChipCenterCoords = new float[2];
public TaskView(Context context) {
this(context, null);
@@ -259,11 +261,22 @@
mIconTouchDelegate = new TransformingTouchDelegate(mIconView);
}
- public TouchDelegate getIconTouchDelegate(MotionEvent event) {
+ /**
+ * Whether the taskview should take the touch event from parent. Events passed to children
+ * that might require special handling.
+ */
+ public boolean offerTouchToChildren(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
computeAndSetIconTouchDelegate();
+ computeAndSetChipTouchDelegate();
}
- return mIconTouchDelegate;
+ if (mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event)) {
+ return true;
+ }
+ if (mChipTouchDelegate != null && mChipTouchDelegate.onTouchEvent(event)) {
+ return true;
+ }
+ return false;
}
private void computeAndSetIconTouchDelegate() {
@@ -278,6 +291,23 @@
(int) (mIconCenterCoords[1] + iconHalfSize));
}
+ private void computeAndSetChipTouchDelegate() {
+ if (mContextualChipWrapper != null) {
+ float chipHalfWidth = mContextualChipWrapper.getWidth() / 2f;
+ float chipHalfHeight = mContextualChipWrapper.getHeight() / 2f;
+ mChipCenterCoords[0] = chipHalfWidth;
+ mChipCenterCoords[1] = chipHalfHeight;
+ getDescendantCoordRelativeToAncestor(mContextualChipWrapper, mActivity.getDragLayer(),
+ mChipCenterCoords,
+ false);
+ mChipTouchDelegate.setBounds(
+ (int) (mChipCenterCoords[0] - chipHalfWidth),
+ (int) (mChipCenterCoords[1] - chipHalfHeight),
+ (int) (mChipCenterCoords[0] + chipHalfWidth),
+ (int) (mChipCenterCoords[1] + chipHalfHeight));
+ }
+ }
+
/**
* The modalness of this view is how it should be displayed when it is shown on its own in the
* modal state of overview.
@@ -712,6 +742,7 @@
mContextualChip.animate().scaleX(1f).scaleY(1f).setDuration(50);
}
if (mContextualChipWrapper != null) {
+ mChipTouchDelegate = new TransformingTouchDelegate(mContextualChipWrapper);
mContextualChipWrapper.animate().alpha(1f).setDuration(50);
}
}
@@ -733,6 +764,7 @@
View oldContextualChipWrapper = mContextualChipWrapper;
mContextualChipWrapper = null;
mContextualChip = null;
+ mChipTouchDelegate = null;
return oldContextualChipWrapper;
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 8da81ac..45aaa1b 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -93,6 +93,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.WorkspaceTouchListener;
@@ -436,10 +437,6 @@
enforceDragParity("onDragEnd", 0, 0);
}
- if (!mDeferRemoveExtraEmptyScreen) {
- removeExtraEmptyScreen(mDragSourceInternal != null);
- }
-
updateChildrenLayersEnabled();
mDragInfo = null;
mOutlineProvider = null;
@@ -657,6 +654,7 @@
convertFinalScreenToEmptyScreenIfNecessary();
if (hasExtraEmptyScreen()) {
removeView(mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID));
+ setCurrentPage(getNextPage());
mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
@@ -1873,6 +1871,18 @@
};
}
}
+ StateManager<LauncherState> stateManager = mLauncher.getStateManager();
+ stateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == NORMAL) {
+ if (!mDeferRemoveExtraEmptyScreen) {
+ removeExtraEmptyScreen(true /* stripEmptyScreens */);
+ }
+ stateManager.removeStateListener(this);
+ }
+ }
+ });
mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId,
lp.cellX, lp.cellY, item.spanX, item.spanY);
@@ -2453,7 +2463,7 @@
Runnable onAnimationCompleteRunnable = new Runnable() {
@Override
public void run() {
- // Normally removeExtraEmptyScreen is called in Workspace#onDragEnd, but when
+ // Normally removeExtraEmptyScreen is called in Workspace#onDrop, but when
// adding an item that may not be dropped right away (due to a config activity)
// we defer the removal until the activity returns.
deferRemoveExtraEmptyScreen();
diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java
index c3d4aeb..ea887cc 100644
--- a/src/com/android/launcher3/WorkspaceLayoutManager.java
+++ b/src/com/android/launcher3/WorkspaceLayoutManager.java
@@ -28,7 +28,7 @@
String TAG = "Launcher.Workspace";
- // The screen id used for the empty screen always present to the right.
+ // The screen id used for the empty screen always present at the end.
int EXTRA_EMPTY_SCREEN_ID = -201;
// The is the first screen. It is always present, even if its empty.
int FIRST_SCREEN_ID = 0;
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 2e5ed3e..29e3404 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -79,7 +79,7 @@
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (mSearchAlgorithm instanceof PluginWrapper) {
((PluginWrapper) mSearchAlgorithm).runOnPluginIfConnected(
- AllAppsSearchPlugin::startedTyping);
+ AllAppsSearchPlugin::startedSearchSession);
}
}
@@ -113,7 +113,13 @@
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ // selectFocusedView should return SearchTargetEvent that is passed onto onClick
if (Launcher.getLauncher(mLauncher).getAppsView().selectFocusedView(v)) {
+ if (mSearchAlgorithm instanceof PluginWrapper) {
+ ((PluginWrapper) mSearchAlgorithm).runOnPluginIfConnected(plugin -> {
+ plugin.onClick(false, null);
+ });
+ }
return true;
}
}
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
index 5112304..70d1b48 100644
--- a/src/com/android/launcher3/model/FirstScreenBroadcast.java
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -17,25 +17,30 @@
import static android.os.Process.myUserHandle;
+import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.mapping;
+
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller.SessionInfo;
+import android.os.UserHandle;
import android.util.Log;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* Helper class to send broadcasts to package installers that have:
@@ -61,26 +66,10 @@
private static final String VERIFICATION_TOKEN_EXTRA = "verificationToken";
- private final MultiHashMap<String, String> mPackagesForInstaller;
+ private final HashMap<PackageUserKey, SessionInfo> mSessionInfoForPackage;
public FirstScreenBroadcast(HashMap<PackageUserKey, SessionInfo> sessionInfoForPackage) {
- mPackagesForInstaller = getPackagesForInstaller(sessionInfoForPackage);
- }
-
- /**
- * @return Map where the key is the package name of the installer, and the value is a list
- * of packages with active sessions for that installer.
- */
- private MultiHashMap<String, String> getPackagesForInstaller(
- HashMap<PackageUserKey, SessionInfo> sessionInfoForPackage) {
- MultiHashMap<String, String> packagesForInstaller = new MultiHashMap<>();
- for (Map.Entry<PackageUserKey, SessionInfo> entry : sessionInfoForPackage.entrySet()) {
- if (myUserHandle().equals(entry.getKey().mUser)) {
- packagesForInstaller.addToList(entry.getValue().getInstallerPackageName(),
- entry.getKey().mPackageName);
- }
- }
- return packagesForInstaller;
+ mSessionInfoForPackage = sessionInfoForPackage;
}
/**
@@ -88,9 +77,15 @@
* first screen.
*/
public void sendBroadcasts(Context context, List<ItemInfo> firstScreenItems) {
- for (Map.Entry<String, ArrayList<String>> entry : mPackagesForInstaller.entrySet()) {
- sendBroadcastToInstaller(context, entry.getKey(), entry.getValue(), firstScreenItems);
- }
+ UserHandle myUser = myUserHandle();
+ mSessionInfoForPackage
+ .values()
+ .stream()
+ .filter(info -> myUser.equals(getUserHandle(info)))
+ .collect(groupingBy(SessionInfo::getInstallerPackageName,
+ mapping(SessionInfo::getAppPackageName, Collectors.toSet())))
+ .forEach((installer, packages) ->
+ sendBroadcastToInstaller(context, installer, packages, firstScreenItems));
}
/**
@@ -99,7 +94,7 @@
* @param firstScreenItems List of items on the first screen.
*/
private void sendBroadcastToInstaller(Context context, String installerPackageName,
- List<String> packages, List<ItemInfo> firstScreenItems) {
+ Set<String> packages, List<ItemInfo> firstScreenItems) {
Set<String> folderItems = new HashSet<>();
Set<String> workspaceItems = new HashSet<>();
Set<String> hotseatItems = new HashSet<>();
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 983ec0c..a9e385f 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -81,7 +81,6 @@
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IOUtils;
import com.android.launcher3.util.LooperIdleLock;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.TraceHelper;
@@ -90,8 +89,10 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CancellationException;
/**
@@ -302,7 +303,7 @@
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
final boolean isSafeMode = pmHelper.isSafeMode();
final boolean isSdCardReady = Utilities.isBootCompleted();
- final MultiHashMap<UserHandle, String> pendingPackages = new MultiHashMap<>();
+ final Set<PackageUserKey> pendingPackages = new HashSet<>();
boolean clearDb = false;
try {
@@ -483,7 +484,7 @@
// SdCard is not ready yet. Package might get available,
// once it is ready.
Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
- pendingPackages.addToList(c.user, targetPkg);
+ pendingPackages.add(new PackageUserKey(targetPkg, c.user));
// Add the icon on the workspace anyway.
allowMissingTarget = true;
} else {
diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java
index a8cc9ad..9b5fac8 100644
--- a/src/com/android/launcher3/model/ModelUtils.java
+++ b/src/com/android/launcher3/model/ModelUtils.java
@@ -36,8 +36,8 @@
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.stream.IntStream;
/**
@@ -56,13 +56,7 @@
ArrayList<T> currentScreenItems,
ArrayList<T> otherScreenItems) {
// Purge any null ItemInfos
- Iterator<T> iter = allWorkspaceItems.iterator();
- while (iter.hasNext()) {
- ItemInfo i = iter.next();
- if (i == null) {
- iter.remove();
- }
- }
+ allWorkspaceItems.removeIf(Objects::isNull);
// Order the set of items by their containers first, this allows use to walk through the
// list sequentially, build up a list of containers that are in the specified screen,
// as well as all items in those containers.
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
index eb3cb52..3798575 100644
--- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -24,12 +24,11 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Map.Entry;
+import java.util.Set;
/**
* Helper class to re-query app status when SD-card becomes available.
@@ -42,10 +41,9 @@
private final LauncherModel mModel;
private final Context mContext;
- private final MultiHashMap<UserHandle, String> mPackages;
+ private final Set<PackageUserKey> mPackages;
- public SdCardAvailableReceiver(LauncherAppState app,
- MultiHashMap<UserHandle, String> packages) {
+ public SdCardAvailableReceiver(LauncherAppState app, Set<PackageUserKey> packages) {
mModel = app.getModel();
mContext = app.getContext();
mPackages = packages;
@@ -55,19 +53,17 @@
public void onReceive(Context context, Intent intent) {
final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
- for (Entry<UserHandle, ArrayList<String>> entry : mPackages.entrySet()) {
- UserHandle user = entry.getKey();
+ for (PackageUserKey puk : mPackages) {
+ UserHandle user = puk.mUser;
final ArrayList<String> packagesRemoved = new ArrayList<>();
final ArrayList<String> packagesUnavailable = new ArrayList<>();
- for (String pkg : new HashSet<>(entry.getValue())) {
- if (!launcherApps.isPackageEnabled(pkg, user)) {
- if (pmHelper.isAppOnSdcard(pkg, user)) {
- packagesUnavailable.add(pkg);
- } else {
- packagesRemoved.add(pkg);
- }
+ if (!launcherApps.isPackageEnabled(puk.mPackageName, user)) {
+ if (pmHelper.isAppOnSdcard(puk.mPackageName, user)) {
+ packagesUnavailable.add(puk.mPackageName);
+ } else {
+ packagesRemoved.add(puk.mPackageName);
}
}
if (!packagesRemoved.isEmpty()) {
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 88006ba..6fedad1 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -25,11 +25,12 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.MultiHashMap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* Handles changes due to shortcut manager updates (deep shortcut changes)
@@ -53,54 +54,53 @@
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
final Context context = app.getContext();
// Find WorkspaceItemInfo's that have changed on the workspace.
- HashSet<ShortcutKey> removedKeys = new HashSet<>();
- MultiHashMap<ShortcutKey, WorkspaceItemInfo> keyToShortcutInfo = new MultiHashMap<>();
- HashSet<String> allIds = new HashSet<>();
+ ArrayList<WorkspaceItemInfo> matchingWorkspaceItems = new ArrayList<>();
synchronized (dataModel) {
dataModel.forAllWorkspaceItemInfos(mUser, si -> {
if ((si.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& mPackageName.equals(si.getIntent().getPackage())) {
- keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si);
- allIds.add(si.getDeepShortcutId());
+ matchingWorkspaceItems.add(si);
}
});
}
- final ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
- if (!keyToShortcutInfo.isEmpty()) {
+ if (!matchingWorkspaceItems.isEmpty()) {
// Update the workspace to reflect the changes to updated shortcuts residing on it.
+ List<String> allLauncherKnownIds = matchingWorkspaceItems.stream()
+ .map(WorkspaceItemInfo::getDeepShortcutId)
+ .distinct()
+ .collect(Collectors.toList());
List<ShortcutInfo> shortcuts = new ShortcutRequest(context, mUser)
- .forPackage(mPackageName, new ArrayList<>(allIds))
+ .forPackage(mPackageName, allLauncherKnownIds)
.query(ShortcutRequest.ALL);
+
+ Set<String> nonPinnedIds = new HashSet<>(allLauncherKnownIds);
+ ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
for (ShortcutInfo fullDetails : shortcuts) {
- ShortcutKey key = ShortcutKey.fromInfo(fullDetails);
- List<WorkspaceItemInfo> workspaceItemInfos = keyToShortcutInfo.remove(key);
if (!fullDetails.isPinned()) {
- // The shortcut was previously pinned but is no longer, so remove it from
- // the workspace and our pinned shortcut counts.
- // Note that we put this check here, after querying for full details,
- // because there's a possible race condition between pinning and
- // receiving this callback.
- removedKeys.add(key);
continue;
}
- for (final WorkspaceItemInfo workspaceItemInfo : workspaceItemInfos) {
- workspaceItemInfo.updateFromDeepShortcutInfo(fullDetails, context);
- app.getIconCache().getShortcutIcon(workspaceItemInfo, fullDetails);
- updatedWorkspaceItemInfos.add(workspaceItemInfo);
- }
+
+ String sid = fullDetails.getId();
+ nonPinnedIds.remove(sid);
+ matchingWorkspaceItems
+ .stream()
+ .filter(itemInfo -> sid.equals(itemInfo.getDeepShortcutId()))
+ .forEach(workspaceItemInfo -> {
+ workspaceItemInfo.updateFromDeepShortcutInfo(fullDetails, context);
+ app.getIconCache().getShortcutIcon(workspaceItemInfo, fullDetails);
+ updatedWorkspaceItemInfos.add(workspaceItemInfo);
+ });
}
- }
- // If there are still entries in keyToShortcutInfo, that means that
- // the corresponding shortcuts weren't passed in onShortcutsChanged(). This
- // means they were cleared, so we remove and unpin them now.
- removedKeys.addAll(keyToShortcutInfo.keySet());
-
- bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
- if (!keyToShortcutInfo.isEmpty()) {
- deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(removedKeys));
+ bindUpdatedWorkspaceItems(updatedWorkspaceItemInfos);
+ if (!nonPinnedIds.isEmpty()) {
+ deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(
+ nonPinnedIds.stream()
+ .map(id -> new ShortcutKey(mPackageName, mUser, id))
+ .collect(Collectors.toSet())));
+ }
}
if (mUpdateIdMap) {
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 5a5f668..76048ba 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -38,7 +38,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -202,20 +201,11 @@
}
public List<WidgetItem> getWidgetsForPackageUser(PackageUserKey packageUserKey) {
- for (WidgetListRowEntry entry : mAllWidgets) {
- if (entry.pkgItem.packageName.equals(packageUserKey.mPackageName)) {
- ArrayList<WidgetItem> widgets = new ArrayList<>(entry.widgets);
- // Remove widgets not associated with the correct user.
- Iterator<WidgetItem> iterator = widgets.iterator();
- while (iterator.hasNext()) {
- if (!iterator.next().user.equals(packageUserKey.mUser)) {
- iterator.remove();
- }
- }
- return widgets.isEmpty() ? null : widgets;
- }
- }
- return null;
+ return mAllWidgets.stream()
+ .filter(row -> row.pkgItem.packageName.equals(packageUserKey.mPackageName))
+ .flatMap(row -> row.widgets.stream())
+ .filter(widget -> packageUserKey.mUser.equals(widget.user))
+ .collect(Collectors.toList());
}
/**
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 7998488..81302ac 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -99,7 +99,7 @@
final List<WidgetItem> widgets =
launcher.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey(
itemInfo.getTargetComponent().getPackageName(), itemInfo.user));
- if (widgets == null) {
+ if (widgets.isEmpty()) {
return null;
}
return new Widgets(launcher, itemInfo);
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index e98af35..d26bb57 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -27,6 +27,7 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import java.util.HashSet;
+import java.util.Set;
/**
* A utility class to check for {@link ItemInfo}
@@ -99,7 +100,7 @@
return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
}
- static ItemInfoMatcher ofShortcutKeys(HashSet<ShortcutKey> keys) {
+ static ItemInfoMatcher ofShortcutKeys(Set<ShortcutKey> keys) {
return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
keys.contains(ShortcutKey.fromItemInfo(info));
}
diff --git a/src/com/android/launcher3/util/MultiHashMap.java b/src/com/android/launcher3/util/MultiHashMap.java
deleted file mode 100644
index b7275c1..0000000
--- a/src/com/android/launcher3/util/MultiHashMap.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * A utility map from keys to an ArrayList of values.
- */
-public class MultiHashMap<K, V> extends HashMap<K, ArrayList<V>> {
-
- public MultiHashMap() { }
-
- public MultiHashMap(int size) {
- super(size);
- }
-
- public void addToList(K key, V value) {
- ArrayList<V> list = get(key);
- if (list == null) {
- list = new ArrayList<>();
- list.add(value);
- put(key, list);
- } else {
- list.add(value);
- }
- }
-
- @Override
- public MultiHashMap<K, V> clone() {
- MultiHashMap<K, V> map = new MultiHashMap<>(size());
- for (Entry<K, ArrayList<V>> entry : entrySet()) {
- map.put(entry.getKey(), new ArrayList<V>(entry.getValue()));
- }
- return map;
- }
-}
diff --git a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
index be20e2d..9949678 100644
--- a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
@@ -16,9 +16,9 @@
package com.android.systemui.plugins;
-import android.os.Bundle;
-
import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
import java.util.List;
import java.util.function.Consumer;
@@ -29,15 +29,28 @@
@ProvidesInterface(action = AllAppsSearchPlugin.ACTION, version = AllAppsSearchPlugin.VERSION)
public interface AllAppsSearchPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_ALL_APPS_SEARCH_ACTIONS";
- int VERSION = 4;
+ int VERSION = 5;
+
+
+ /**
+ * Send signal when user enters all apps.
+ */
+ void startAllAppsSession();
/**
* Send signal when user starts typing.
*/
- void startedTyping();
+ void startedSearchSession();
/**
* Send over the query and get the search results.
*/
- void performSearch(String query, Consumer<List<Bundle>> results);
-}
+ void performSearch(String query, Consumer<List<SearchTarget>> results);
+
+ void onClick(boolean isTouch, SearchTargetEvent event);
+
+ /**
+ * Send signal when user exits all apps.
+ */
+ void endAllAppsSession();
+}
\ No newline at end of file
diff --git a/src_plugins/com/android/systemui/plugins/OWNERS b/src_plugins/com/android/systemui/plugins/OWNERS
deleted file mode 100644
index 0514999..0000000
--- a/src_plugins/com/android/systemui/plugins/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# When changing interface for this plugin OR when increasing version code, please add Alex
-# Only add other owners if Alex is not available
-per-file AllAppsSearchPlugin.java, globs = set noparent
-per-file AllAppsSearchPlugin.java = alexmang@google.com, hyunyoungs@google.com, sunnygoyal@google.com, twickham@google.com
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
new file mode 100644
index 0000000..913fc0e
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
@@ -0,0 +1,99 @@
+/*
+ * 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.systemui.plugins.shared;
+
+import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
+
+import java.util.List;
+
+/**
+ * Used to return all apps search targets.
+ */
+public class SearchTarget implements Comparable<SearchTarget> {
+
+ public enum ViewType {
+ TOP_HIT(0),
+ HERO(1),
+ DETAIL(2),
+ ROW(3),
+ ROW_WITH_BUTTON(4),
+ SLICE(5);
+
+ private final int mId;
+ ViewType(int id) {
+ mId = id;
+ }
+
+ public int get() {
+ return mId;
+ }
+ }
+
+ public enum ItemType {
+ PLAY_RESULTS(0, "Play Store", ViewType.DETAIL),
+ SETTINGS_ROW(1, "Settings", ViewType.ROW),
+ SETTINGS_SLICE(2, "Settings", ViewType.SLICE),
+ APP(3, "", ViewType.TOP_HIT),
+ APP_HERO(4, "", ViewType.HERO);
+
+ private final int mId;
+ private final String mTitle;
+ private final ViewType mViewType;
+
+ ItemType(int id, String title, ViewType type) {
+ mId = id;
+ mTitle = title;
+ mViewType = type;
+ }
+
+ public ViewType getViewType() {
+ return mViewType;
+ }
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public int getId() {
+ return mId;
+ }
+ }
+
+ public ItemType type;
+ public List<ShortcutInfo> shortcuts;
+ public Bundle bundle;
+ public float score;
+
+ /**
+ * Constructor to create the search target. Bundle is currently temporary to hold
+ * search target primitives that cannot be expressed as java primitive objects
+ * or AOSP native objects.
+ *
+ */
+ public SearchTarget(ItemType itemType, List<ShortcutInfo> shortcuts,
+ Bundle bundle, float score) {
+ this.type = itemType;
+ this.shortcuts = shortcuts;
+ this.bundle = bundle;
+ this.score = score;
+ }
+
+ @Override
+ public int compareTo(SearchTarget o) {
+ return Float.compare(o.score, score);
+ }
+}
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java
new file mode 100644
index 0000000..00aacd0
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java
@@ -0,0 +1,39 @@
+/*
+ * 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.systemui.plugins.shared;
+
+import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
+
+/**
+ * Event used for the feedback loop to the plugin. (and future aiai)
+ */
+public class SearchTargetEvent {
+ public SearchTarget.ItemType type;
+ public ShortcutInfo shortcut;
+ public Bundle bundle;
+ public float score;
+
+ public SearchTargetEvent(SearchTarget.ItemType itemType,
+ ShortcutInfo shortcut,
+ Bundle bundle,
+ float score) {
+ this.type = itemType;
+ this.shortcut = shortcut;
+ this.bundle = bundle;
+ this.score = score;
+ }
+}
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index a64df62..34ebbac 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -26,7 +26,6 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
-import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.widget.WidgetItemComparator;
@@ -36,11 +35,12 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* Widgets data model that is used by the adapters of the widget views and controllers.
@@ -57,9 +57,7 @@
private static final boolean DEBUG = false;
/* Map of widgets and shortcuts that are tracked per package. */
- private final MultiHashMap<PackageItemInfo, WidgetItem> mWidgetsList = new MultiHashMap<>();
-
- private AppFilter mAppFilter;
+ private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsList = new HashMap<>();
/**
* Returns a list of {@link WidgetListRowEntry}. All {@link WidgetItem} in a single row
@@ -74,8 +72,9 @@
AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context);
WidgetItemComparator widgetComparator = new WidgetItemComparator();
- for (Map.Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
- WidgetListRowEntry row = new WidgetListRowEntry(entry.getKey(), entry.getValue());
+ for (Map.Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
+ WidgetListRowEntry row = new WidgetListRowEntry(
+ entry.getKey(), new ArrayList<>(entry.getValue()));
row.titleSectionName = (row.pkgItem.title == null) ? "" :
indexer.computeSectionName(row.pkgItem.title);
Collections.sort(row.widgets, widgetComparator);
@@ -146,77 +145,42 @@
if (packageUser == null) {
mWidgetsList.clear();
} else {
- // Only clear the widgets for the given package/user.
- PackageItemInfo packageItem = null;
- for (PackageItemInfo item : mWidgetsList.keySet()) {
- if (item.packageName.equals(packageUser.mPackageName)) {
- packageItem = item;
- break;
- }
- }
+ PackageItemInfo packageItem = mWidgetsList.keySet()
+ .stream()
+ .filter(item -> item.packageName.equals(packageUser.mPackageName))
+ .findFirst()
+ .orElse(null);
if (packageItem != null) {
// We want to preserve the user that was on the packageItem previously,
// so add it to tmpPackageItemInfos here to avoid creating a new entry.
tmpPackageItemInfos.put(packageItem.packageName, packageItem);
- Iterator<WidgetItem> widgetItemIterator = mWidgetsList.get(packageItem).iterator();
- while (widgetItemIterator.hasNext()) {
- WidgetItem nextWidget = widgetItemIterator.next();
- if (nextWidget.componentName.getPackageName().equals(packageUser.mPackageName)
- && nextWidget.user.equals(packageUser.mUser)) {
- widgetItemIterator.remove();
- }
- }
+ // Add the widgets for other users in the rawList as it only contains widgets for
+ // packageUser
+ List<WidgetItem> otherUserItems = mWidgetsList.remove(packageItem);
+ otherUserItems.removeIf(w -> w.user.equals(packageUser.mUser));
+ rawWidgetsShortcuts.addAll(otherUserItems);
}
}
- InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
UserHandle myUser = Process.myUserHandle();
// add and update.
- for (WidgetItem item : rawWidgetsShortcuts) {
- if (item.widgetInfo != null) {
- if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) {
- // Widget is hidden from picker
- continue;
- }
-
- // Ensure that all widgets we show can be added on a workspace of this size
- int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX);
- int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY);
- if (minSpanX > idp.numColumns || minSpanY > idp.numRows) {
- if (DEBUG) {
- Log.d(TAG, String.format(
- "Widget %s : (%d X %d) can't fit on this device",
- item.componentName, minSpanX, minSpanY));
+ mWidgetsList.putAll(rawWidgetsShortcuts.stream()
+ .filter(new WidgetValidityCheck(app))
+ .collect(Collectors.groupingBy(item -> {
+ String packageName = item.componentName.getPackageName();
+ PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
+ if (pInfo == null) {
+ pInfo = new PackageItemInfo(packageName);
+ pInfo.user = item.user;
+ tmpPackageItemInfos.put(packageName, pInfo);
+ } else if (!myUser.equals(pInfo.user)) {
+ // Keep updating the user, until we get the primary user.
+ pInfo.user = item.user;
}
- continue;
- }
- }
-
- if (mAppFilter == null) {
- mAppFilter = AppFilter.newInstance(app.getContext());
- }
- if (!mAppFilter.shouldShowApp(item.componentName)) {
- if (DEBUG) {
- Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",
- item.componentName));
- }
- continue;
- }
-
- String packageName = item.componentName.getPackageName();
- PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
- if (pInfo == null) {
- pInfo = new PackageItemInfo(packageName);
- pInfo.user = item.user;
- tmpPackageItemInfos.put(packageName, pInfo);
- } else if (!myUser.equals(pInfo.user)) {
- // Keep updating the user, until we get the primary user.
- pInfo.user = item.user;
- }
- mWidgetsList.addToList(pInfo, item);
- }
+ return pInfo;
+ })));
// Update each package entry
IconCache iconCache = app.getIconCache();
@@ -227,9 +191,9 @@
public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
LauncherAppState app) {
- for (Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
+ for (Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
if (packageNames.contains(entry.getKey().packageName)) {
- ArrayList<WidgetItem> items = entry.getValue();
+ List<WidgetItem> items = entry.getValue();
int count = items.size();
for (int i = 0; i < count; i++) {
WidgetItem item = items.get(i);
@@ -249,7 +213,7 @@
public WidgetItem getWidgetProviderInfoByProviderName(
ComponentName providerName) {
- ArrayList<WidgetItem> widgetsList = mWidgetsList.get(
+ List<WidgetItem> widgetsList = mWidgetsList.get(
new PackageItemInfo(providerName.getPackageName()));
if (widgetsList == null) {
return null;
@@ -262,4 +226,46 @@
}
return null;
}
+
+ private static class WidgetValidityCheck implements Predicate<WidgetItem> {
+
+ private final InvariantDeviceProfile mIdp;
+ private final AppFilter mAppFilter;
+
+ WidgetValidityCheck(LauncherAppState app) {
+ mIdp = app.getInvariantDeviceProfile();
+ mAppFilter = AppFilter.newInstance(app.getContext());
+ }
+
+ @Override
+ public boolean test(WidgetItem item) {
+ if (item.widgetInfo != null) {
+ if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) {
+ // Widget is hidden from picker
+ return false;
+ }
+
+ // Ensure that all widgets we show can be added on a workspace of this size
+ int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX);
+ int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY);
+ if (minSpanX > mIdp.numColumns || minSpanY > mIdp.numRows) {
+ if (DEBUG) {
+ Log.d(TAG, String.format(
+ "Widget %s : (%d X %d) can't fit on this device",
+ item.componentName, minSpanX, minSpanY));
+ }
+ return false;
+ }
+ }
+ if (!mAppFilter.shouldShowApp(item.componentName)) {
+ if (DEBUG) {
+ Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",
+ item.componentName));
+ }
+ return false;
+ }
+
+ return true;
+ }
+ }
}
\ No newline at end of file