Merge "Moving package installer initialization to worker thread" into ub-launcher3-master
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index 810f4e3..f92b3e3 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -63,7 +63,6 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
-import java.util.function.Consumer;
/**
* Data model for digital wellbeing status of apps.
@@ -222,9 +221,8 @@
reloadLauncherInNormalMode(context);
return;
}
- runWithMinimalDeviceConfigs((bundle) -> {
- if (bundle.getInt(EXTRA_MINIMAL_DEVICE_STATE, UNKNOWN_MINIMAL_DEVICE_STATE)
- == IN_MINIMAL_DEVICE) {
+ mWorkerHandler.post(() -> {
+ if (isInMinimalDeviceMode()) {
reloadLauncherInMinimalMode(context);
} else {
reloadLauncherInNormalMode(context);
@@ -253,31 +251,30 @@
.authority(mWellbeingProviderPkg + ".api");
}
- /**
- * Fetch most up-to-date minimal device config.
- */
@WorkerThread
- private void runWithMinimalDeviceConfigs(Consumer<Bundle> consumer) {
+ private boolean isInMinimalDeviceMode() {
if (!FeatureFlags.ENABLE_MINIMAL_DEVICE.get()) {
- return;
+ return false;
}
if (DEBUG || mIsInTest) {
- Log.d(TAG, "runWithMinimalDeviceConfigs() called");
+ Log.d(TAG, "isInMinimalDeviceMode() called");
}
Preconditions.assertNonUiThread();
final Uri contentUri = apiBuilder().build();
- final Bundle remoteBundle;
try (ContentProviderClient client = mContext.getContentResolver()
.acquireUnstableContentProviderClient(contentUri)) {
- remoteBundle = client.call(
+ final Bundle remoteBundle = client == null ? null : client.call(
METHOD_GET_MINIMAL_DEVICE_CONFIG, null /* args */, null /* extras */);
- consumer.accept(remoteBundle);
+ return remoteBundle != null
+ && remoteBundle.getInt(EXTRA_MINIMAL_DEVICE_STATE,
+ UNKNOWN_MINIMAL_DEVICE_STATE) == IN_MINIMAL_DEVICE;
} catch (Exception e) {
Log.e(TAG, "Failed to retrieve data from " + contentUri + ": " + e);
if (mIsInTest) throw new RuntimeException(e);
}
- if (DEBUG || mIsInTest) Log.i(TAG, "runWithMinimalDeviceConfigs(): finished");
+ if (DEBUG || mIsInTest) Log.i(TAG, "isInMinimalDeviceMode(): finished");
+ return false;
}
private boolean updateActions(String... packageNames) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 26ad377..22e6755 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -434,9 +434,13 @@
mOnDeferredActivityLaunch);
mGestureState.runOnceAtState(STATE_END_TARGET_SET,
- () -> mDeviceState.getRotationTouchHelper().
- onEndTargetCalculated(mGestureState.getEndTarget(),
- mActivityInterface));
+ () -> {
+ mDeviceState.getRotationTouchHelper()
+ .onEndTargetCalculated(mGestureState.getEndTarget(),
+ mActivityInterface);
+
+ mRecentsView.onGestureEndTargetCalculated(mGestureState.getEndTarget());
+ });
notifyGestureStartedAsync();
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index f5f5259..8f2356c 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.fallback;
+import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
@@ -27,6 +28,7 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.quickstep.FallbackActivityInterface;
+import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
@@ -74,14 +76,14 @@
}
/**
- * When the gesture ends and recents view become interactive, we also remove the temporary
+ * When the gesture ends and we're going to recents view, we also remove the temporary
* invisible tile added for the home task. This also pushes the remaining tiles back
* to the center.
*/
@Override
- public void onGestureAnimationEnd() {
- super.onGestureAnimationEnd();
- if (mHomeTaskInfo != null) {
+ public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
+ super.onGestureEndTargetCalculated(endTarget);
+ if (mHomeTaskInfo != null && endTarget == RECENTS) {
TaskView tv = getTaskView(mHomeTaskInfo.taskId);
if (tv != null) {
PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 0362377..b617817 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -118,6 +118,7 @@
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.ViewPool;
import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.RecentsModel;
@@ -1183,7 +1184,14 @@
}
/**
- * Called when a gesture from an app has finished.
+ * Called when a gesture from an app has finished, and an end target has been determined.
+ */
+ public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
+
+ }
+
+ /**
+ * Called when a gesture from an app has finished, and the animation to the target has ended.
*/
public void onGestureAnimationEnd() {
if (mOrientationState.setGestureActive(false)) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 656d59e..d47eba6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -246,7 +246,7 @@
setScaleX(taskView.getScaleX());
setScaleY(taskView.getScaleY());
boolean canActivityRotate = taskView.getRecentsView()
- .mOrientationState.canRecentsActivityRotate();
+ .mOrientationState.isRecentsActivityRotationAllowed();
mOptionLayout.setOrientation(orientationHandler
.getTaskMenuLayoutOrientation(canActivityRotate, mOptionLayout));
setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top,
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index ecd4e2b..c5863c1 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -201,6 +201,12 @@
@PortraitLandscape
public void testOverviewActions() throws Exception {
if (mLauncher.getNavigationModel() != NavigationModel.TWO_BUTTON) {
+ // Experimenting for b/165029151:
+ final Overview overview = mLauncher.pressHome().switchToOverview();
+ if (overview.hasTasks()) overview.dismissAllTasks();
+ mLauncher.pressHome();
+ //
+
startTestAppsWithCheck();
OverviewActions actionsView =
mLauncher.pressHome().switchToOverview().getOverviewActions();
diff --git a/res/layout/search_result_thumbnail.xml b/res/layout/search_result_thumbnail.xml
new file mode 100644
index 0000000..0cc5a29
--- /dev/null
+++ b/res/layout/search_result_thumbnail.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.launcher3.views.ThumbnailSearchResultView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="125dp"
+ android:layout_height="125dp"/>
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 90566f3..1cf2e89 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -18,6 +18,7 @@
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
@@ -70,6 +71,7 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -88,9 +90,10 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
+import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.CallSuper;
@@ -117,6 +120,7 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.FolderGridOrganizer;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
@@ -269,6 +273,8 @@
private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 1;
private static final int SCRIM_VIEW_ALPHA_CHANNEL_INDEX = 0;
+ private static final int THEME_CROSS_FADE_ANIMATION_DURATION = 375;
+
private LauncherAppTransitionManager mAppTransitionManager;
private Configuration mOldConfig;
@@ -400,6 +406,7 @@
inflateRootView(R.layout.launcher);
setupViews();
+ crossFadeWithPreviousAppearance();
mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
@@ -476,7 +483,7 @@
() -> getStateManager().goToState(NORMAL));
if (Utilities.ATLEAST_R) {
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
+ getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
}
mLifecycleRegistry = new LifecycleRegistry(this);
@@ -1364,6 +1371,18 @@
closeContextMenu();
}
+ @Override
+ public Object onRetainNonConfigurationInstance() {
+ int width = mDragLayer.getWidth();
+ int height = mDragLayer.getHeight();
+
+ if (width <= 0 || height <= 0) {
+ return null;
+ }
+
+ return BitmapRenderer.createHardwareBitmap(width, height, mDragLayer::draw);
+ }
+
public AllAppsTransitionController getAllAppsController() {
return mAllAppsController;
}
@@ -2758,4 +2777,40 @@
void onLauncherResume();
}
+
+ /**
+ * Cross-fades the launcher's updated appearance with its previous appearance.
+ *
+ * This method is used to cross-fade UI updates on activity creation, specifically dark mode
+ * updates.
+ */
+ private void crossFadeWithPreviousAppearance() {
+ Bitmap previousAppearanceBitmap = (Bitmap) getLastNonConfigurationInstance();
+
+ if (previousAppearanceBitmap == null) {
+ return;
+ }
+
+ ImageView crossFadeHelper = new ImageView(this);
+
+ crossFadeHelper.setImageBitmap(previousAppearanceBitmap);
+ crossFadeHelper.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+
+ InsettableFrameLayout.LayoutParams layoutParams = new InsettableFrameLayout.LayoutParams(
+ InsettableFrameLayout.LayoutParams.MATCH_PARENT,
+ InsettableFrameLayout.LayoutParams.MATCH_PARENT);
+
+ layoutParams.ignoreInsets = true;
+
+ crossFadeHelper.setLayoutParams(layoutParams);
+
+ getRootView().addView(crossFadeHelper);
+
+ crossFadeHelper
+ .animate()
+ .setDuration(THEME_CROSS_FADE_ANIMATION_DURATION)
+ .alpha(0f)
+ .withEndAction(() -> getRootView().removeView(crossFadeHelper))
+ .start();
+ }
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index dea2a8d..43ccb79 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -133,6 +133,10 @@
public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
public static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR";
+ // An intent extra to indicate the launch source by launcher.
+ public static final String EXTRA_WALLPAPER_LAUNCH_SOURCE =
+ "com.android.wallpaper.LAUNCH_SOURCE";
+
public static boolean IS_RUNNING_IN_TEST_HARNESS =
ActivityManager.isRunningInTestHarness();
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index d1340fa..e08bd5b 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -96,6 +96,8 @@
public static final int VIEW_TYPE_SEARCH_PEOPLE = 1 << 11;
+ public static final int VIEW_TYPE_SEARCH_THUMBNAIL = 1 << 12;
+
// Common view type masks
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
@@ -186,6 +188,7 @@
|| viewType == VIEW_TYPE_SEARCH_SLICE
|| viewType == VIEW_TYPE_SEARCH_ROW
|| viewType == VIEW_TYPE_SEARCH_PEOPLE
+ || viewType == VIEW_TYPE_SEARCH_THUMBNAIL
|| viewType == VIEW_TYPE_SEARCH_SHORTCUT;
}
}
@@ -307,15 +310,21 @@
@Override
public int getSpanSize(int position) {
- if (isIconViewType(mApps.getAdapterItems().get(position).viewType)) {
- return 1;
+ int viewType = mApps.getAdapterItems().get(position).viewType;
+ if (isIconViewType(viewType)) {
+ return 1 * SPAN_MULTIPLIER;
+ } else if (viewType == VIEW_TYPE_SEARCH_THUMBNAIL) {
+ return mAppsPerRow;
} else {
// Section breaks span the full width
- return mAppsPerRow;
+ return mAppsPerRow * SPAN_MULTIPLIER;
}
}
}
+ // multiplier to support adapter item column count that is not mAppsPerRow.
+ private static final int SPAN_MULTIPLIER = 3;
+
private final BaseDraggingActivity mLauncher;
private final LayoutInflater mLayoutInflater;
private final AlphabeticalAppsList mApps;
@@ -352,7 +361,7 @@
public void setAppsPerRow(int appsPerRow) {
mAppsPerRow = appsPerRow;
- mGridLayoutMgr.setSpanCount(mAppsPerRow);
+ mGridLayoutMgr.setSpanCount(mAppsPerRow * SPAN_MULTIPLIER);
}
/**
@@ -444,6 +453,9 @@
case VIEW_TYPE_SEARCH_PEOPLE:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_people_item, parent, false));
+ case VIEW_TYPE_SEARCH_THUMBNAIL:
+ return new ViewHolder(mLayoutInflater.inflate(
+ R.layout.search_result_thumbnail, parent, false));
default:
throw new RuntimeException("Unexpected view type");
}
@@ -525,6 +537,7 @@
case VIEW_TYPE_SEARCH_ROW:
case VIEW_TYPE_SEARCH_SHORTCUT:
case VIEW_TYPE_SEARCH_PEOPLE:
+ case VIEW_TYPE_SEARCH_THUMBNAIL:
PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
payloadResultView.applyAdapterInfo(
(AdapterItemWithPayload) mApps.getAdapterItems().get(position));
@@ -553,7 +566,6 @@
}
}
-
@Override
public boolean onFailedToRecycleView(ViewHolder holder) {
// Always recycle and we will reset the view when it is bound
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 2627149..4175280 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -177,8 +177,8 @@
"SEPARATE_RECENTS_ACTIVITY", false,
"Uses a separate recents activity instead of using the integrated recents+Launcher UI");
- public static final BooleanFlag ENABLE_MINIMAL_DEVICE = new DeviceFlag(
- "ENABLE_MINIMAL_DEVICE", false,
+ public static final BooleanFlag ENABLE_MINIMAL_DEVICE = getDebugFlag(
+ "ENABLE_MINIMAL_DEVICE", true,
"Allow user to toggle minimal device mode in launcher.");
public static void initialize(Context context) {
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index 2d7d6b0..5aab41a 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -21,10 +21,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
-import android.util.Log;
import android.util.LongSparseArray;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SimpleBroadcastReceiver;
@@ -104,9 +102,6 @@
mUsers = null;
mUserToSerialMap = null;
}
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.WORK_PROFILE_REMOVED, "Work profile removed", new Exception());
- }
}
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index b2d0081..7f76355 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -106,5 +106,4 @@
public static final String PAUSE_NOT_DETECTED = "b/139891609";
public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
public static final String NO_SWIPE_TO_HOME = "b/158017601";
- public static final String WORK_PROFILE_REMOVED = "b/159671700";
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 3ec20d5..a8caa9e 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -16,6 +16,7 @@
package com.android.launcher3.views;
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR;
+import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_LAUNCH_SOURCE;
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS;
@@ -211,7 +212,8 @@
Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.putExtra(EXTRA_WALLPAPER_OFFSET,
- launcher.getWorkspace().getWallpaperOffsetForCenterPage());
+ launcher.getWorkspace().getWallpaperOffsetForCenterPage())
+ .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher");
if (!Utilities.existsStyleWallpapers(launcher)) {
intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only");
} else {
diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
new file mode 100644
index 0000000..decc861
--- /dev/null
+++ b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
@@ -0,0 +1,81 @@
+/*
+ * 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.views;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.AttributeSet;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.util.Themes;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+/**
+ * A view representing a high confidence app search result that includes shortcuts
+ */
+public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppCompatImageView
+ implements AllAppsSearchBarController.PayloadResultHandler<Bundle> {
+
+ Intent mIntent;
+ AllAppsSearchPlugin mPlugin;
+
+ public ThumbnailSearchResultView(Context context) {
+ super(context);
+ }
+
+ public ThumbnailSearchResultView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ThumbnailSearchResultView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ private void handleSelection(int eventType) {
+ Launcher launcher = Launcher.getLauncher(getContext());
+ launcher.startActivitySafely(this, mIntent, null);
+
+ SearchTargetEvent event = new SearchTargetEvent(
+ SearchTarget.ItemType.SCREENSHOT, eventType);
+ if (mPlugin != null) {
+ mPlugin.notifySearchTargetEvent(event);
+ }
+ }
+
+ @Override
+ public void applyAdapterInfo(AdapterItemWithPayload<Bundle> adapterItem) {
+ RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null,
+ (Bitmap) adapterItem.getPayload().getParcelable("bitmap"));
+ drawable.setCornerRadius(Themes.getDialogCornerRadius(getContext()));
+ setImageDrawable(drawable);
+ mIntent = new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(adapterItem.getPayload().getString("uri")))
+ .setType("image/*")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mPlugin = adapterItem.getPlugin();
+ adapterItem.setSelectionHandler(this::handleSelection);
+ }
+}
diff --git a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
index 437cf3c..48369a4 100644
--- a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
@@ -16,6 +16,9 @@
package com.android.systemui.plugins;
+import android.app.Activity;
+import android.view.View;
+
import com.android.systemui.plugins.annotations.ProvidesInterface;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
@@ -29,22 +32,26 @@
@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 = 5;
+ int VERSION = 6;
+ void setup(Activity activity, View view);
/**
- * Send signal when user enters all apps.
+ * Send launcher state related signals.
*/
- void startAllAppsSession();
+ void onStateTransitionStart(int fromState, int toState);
+ void onStateTransitionComplete(int state);
/**
- * Send signal when user starts typing.
+ * Send launcher window focus and visibility changed signals.
+ */
+ void onWindowFocusChanged(boolean hasFocus);
+ void onWindowVisibilityChanged(int visibility);
+
+ /**
+ * Send signal when user starts typing, perform search, when search ends
*/
void startedSearchSession();
-
- /**
- * Send over the query and get the search results.
- */
void performSearch(String query, Consumer<List<SearchTarget>> results);
/**
@@ -53,7 +60,8 @@
void notifySearchTargetEvent(SearchTargetEvent event);
/**
- * Send signal when user exits all apps.
+ * Launcher activity lifecycle callbacks
*/
- void endAllAppsSession();
+ void onResume(int state);
+ void onStop(int state);
}
\ No newline at end of file
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
index c6b8300..9144976 100644
--- a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
@@ -26,14 +26,52 @@
public class SearchTarget implements Comparable<SearchTarget> {
public enum ViewType {
+
+ /**
+ * Consists of N number of icons. (N: launcher column count)
+ */
TOP_HIT(0),
+
+ /**
+ * Consists of 1 icon and two subsidiary icons.
+ */
HERO(1),
+
+ /**
+ * Main/sub/breadcrumb texts are rendered.
+ */
DETAIL(2),
+
+ /**
+ * Consists of an icon, three detail strings.
+ */
ROW(3),
+
+ /**
+ * Consists of an icon, three detail strings and a button.
+ */
ROW_WITH_BUTTON(4),
+
+ /**
+ * Consists of a single slice view
+ */
SLICE(5),
+
+ /**
+ * Similar to hero section.
+ */
SHORTCUT(6),
- PEOPLE(7);
+
+ /**
+ * Person icon and handling app icons are rendered.
+ */
+ PEOPLE(7),
+
+ /**
+ * N number of 1x1 ratio thumbnail is rendered.
+ * (current N = 3)
+ */
+ THUMBNAIL(8);
private final int mId;
ViewType(int id) {
@@ -52,9 +90,12 @@
APP(3, "", ViewType.TOP_HIT),
APP_HERO(4, "", ViewType.HERO),
SHORTCUT(5, "Shortcuts", ViewType.SHORTCUT),
- PEOPLE(6, "People", ViewType.PEOPLE);
+ PEOPLE(6, "People", ViewType.PEOPLE),
+ SCREENSHOT(7, "Screenshots", ViewType.THUMBNAIL);
private final int mId;
+
+ /** Used to render section title. */
private final String mTitle;
private final ViewType mViewType;
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index f5f93c4..e51c1ca 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -24,7 +24,6 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.Log;
import android.widget.TextView;
import androidx.test.filters.LargeTest;
@@ -35,7 +34,6 @@
import com.android.launcher3.allapps.AllAppsPagedView;
import com.android.launcher3.allapps.WorkModeSwitch;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.WorkEduView;
import org.junit.After;
@@ -135,9 +133,6 @@
workEduView.findViewById(R.id.proceed).callOnClick();
});
- executeOnLauncher(launcher -> Log.d(TestProtocol.WORK_PROFILE_REMOVED,
- "Work profile status: " + launcher.getAppsView().isPersonalTabVisible()));
-
// verify work edu is seen next
waitForLauncherCondition("Launcher did not show the next edu screen", l ->
((AllAppsPagedView) l.getAppsView().getContentView()).getCurrentPage() == WORK_PAGE