Merge "Add shadow radius to windows during app launch / close animations." into ub-launcher3-master
diff --git a/Android.bp b/Android.bp
index e132854..081f485 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,14 +35,12 @@
name: "launcher_log_protos_lite",
srcs: [
"protos/*.proto",
- "proto_overrides/*.proto",
],
sdk_version: "current",
proto: {
type: "lite",
local_include_dirs:[
"protos",
- "proto_overrides",
],
},
static_libs: ["libprotobuf-java-lite"],
diff --git a/proto_overrides/launcher_log_extension.proto b/proto_overrides/launcher_log_extension.proto
deleted file mode 100644
index 2995aa2..0000000
--- a/proto_overrides/launcher_log_extension.proto
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-syntax = "proto2";
-
-option java_package = "com.android.launcher3.userevent";
-option java_outer_classname = "LauncherLogExtensions";
-
-package userevent;
-
-//
-// Use this to add any app specific extensions to the proto.
-//
-message LauncherEventExtension {
-}
-
-message TargetExtension {
-}
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 769d298..b913ba4 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -149,6 +149,21 @@
<!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go far enough. [CHAR LIMIT=100] -->
<string name="assistant_gesture_feedback_swipe_not_long_enough" translatable="false">Try swiping further</string>
+ <!-- Title shown in sandbox mode part of gesture tutorial. [CHAR LIMIT=30] -->
+ <string name="sandbox_mode_title" translatable="false">Sandbox Mode</string>
+ <!-- Subtitle shown in sandbox mode part of gesture tutorial. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_subtitle" translatable="false">Try any navigation gesture</string>
+ <!-- Feedback shown in sandbox mode when the back gesture is successfully issued. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_back_gesture_feedback_successful" translatable="false">Back gesture successful</string>
+ <!-- Feedback shown in sandbox mode when the assistant gesture is a successfully issued. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_assistant_gesture_feedback_successful" translatable="false">Assistant gesture successful</string>
+ <!-- Feedback shown in sandbox mode when the home gesture is a successfully issued. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_home_gesture_feedback_successful" translatable="false">Home gesture successful</string>
+ <!-- Feedback shown in sandbox mode when the overview gesture is a successfully issued. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_overview_gesture_feedback_successful" translatable="false">Overview gesture successful</string>
+ <!-- Feedback shown in sandbox mode when the back gesture swipe is too far from the edge. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_back_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the left/right edge of the screen</string>
+
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
<!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 68111d2..54c2383 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -22,6 +22,8 @@
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Intent;
@@ -307,4 +309,10 @@
public void setHintUserWillBeActive() {
addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
}
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ InteractionJankMonitorWrapper.init(getWindow().getDecorView());
+ }
}
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 199cf63..75355c9 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -34,8 +34,7 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@TargetApi(Build.VERSION_CODES.P)
-public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat,
- WrappedAnimationRunnerImpl {
+public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
private static final String TAG = "LauncherAnimationRunner";
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 6e567f7..df1833d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -66,6 +66,7 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.shortcuts.DeepShortcutView;
@@ -81,6 +82,7 @@
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
@@ -799,6 +801,36 @@
== PackageManager.PERMISSION_GRANTED;
}
+ private void addCujInstrumentation(Animator anim, int cuj, String transition) {
+ if (Trace.isEnabled()) {
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ Trace.beginAsyncSection(transition, 0);
+ InteractionJankMonitorWrapper.begin(cuj);
+ super.onAnimationStart(animation);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ InteractionJankMonitorWrapper.cancel(cuj);
+ }
+
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ InteractionJankMonitorWrapper.end(cuj);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
+ }
+ });
+ }
+ }
+
/**
* Remote animation runner for animation from the app to Launcher, including recents.
*/
@@ -863,21 +895,9 @@
// is initialized.
if (launcherIsATargetWithMode(appTargets, MODE_OPENING)
|| mLauncher.isForceInvisible()) {
- if (Trace.isEnabled()) {
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
- super.onAnimationStart(animation);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
- }
- });
- }
+ addCujInstrumentation(
+ anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME,
+ TRANSITION_OPEN_LAUNCHER);
// Only register the content animation for cancellation when state changes
mLauncher.getStateManager().setCurrentAnimation(anim);
@@ -946,25 +966,12 @@
launcherClosing);
}
- if (Trace.isEnabled()) {
- final String section =
- launchingFromRecents
- ? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON;
-
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- Trace.beginAsyncSection(section, 0);
- super.onAnimationStart(animation);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- Trace.endAsyncSection(section, 0);
- }
- });
- }
+ addCujInstrumentation(anim,
+ launchingFromRecents
+ ? InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_RECENTS
+ : InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_ICON,
+ launchingFromRecents
+ ? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON);
if (launcherClosing) {
anim.addListener(mForceInvisibleListener);
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index f92b3e3..a9fc1aa 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -18,8 +18,7 @@
import static android.content.ContentResolver.SCHEME_CONTENT;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.createAndStartNewLooper;
+import static com.android.launcher3.Utilities.newContentObserver;
import android.annotation.TargetApi;
import android.app.RemoteAction;
@@ -35,7 +34,7 @@
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
-import android.os.Message;
+import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -43,7 +42,7 @@
import android.util.Log;
import androidx.annotation.MainThread;
-import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.launcher3.BaseDraggingActivity;
@@ -55,6 +54,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.RemoteActionShortcut;
import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.util.BgObjectWithLooper;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
@@ -68,15 +68,11 @@
* Data model for digital wellbeing status of apps.
*/
@TargetApi(Build.VERSION_CODES.Q)
-public final class WellbeingModel {
+public final class WellbeingModel extends BgObjectWithLooper {
private static final String TAG = "WellbeingModel";
private static final int[] RETRY_TIMES_MS = {5000, 15000, 30000};
private static final boolean DEBUG = false;
- private static final int MSG_PACKAGE_ADDED = 1;
- private static final int MSG_PACKAGE_REMOVED = 2;
- private static final int MSG_FULL_REFRESH = 3;
-
private static final int UNKNOWN_MINIMAL_DEVICE_STATE = 0;
private static final int IN_MINIMAL_DEVICE = 2;
@@ -98,9 +94,9 @@
private final Context mContext;
private final String mWellbeingProviderPkg;
- private final Handler mWorkerHandler;
- private final ContentObserver mContentObserver;
+ private Handler mWorkerHandler;
+ private ContentObserver mContentObserver;
private final Object mModelLock = new Object();
// Maps the action Id to the corresponding RemoteAction
@@ -111,60 +107,67 @@
private WellbeingModel(final Context context) {
mContext = context;
- mWorkerHandler =
- new Handler(createAndStartNewLooper("WellbeingHandler"), this::handleMessage);
-
mWellbeingProviderPkg = mContext.getString(R.string.wellbeing_provider_pkg);
- mContentObserver = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (DEBUG || mIsInTest) {
- Log.d(TAG, "ContentObserver.onChange() called with: selfChange = ["
- + selfChange + "], uri = [" + uri + "]");
- }
- Preconditions.assertUIThread();
+ initializeInBackground("WellbeingHandler");
+ }
- if (uri.getPath().contains(PATH_ACTIONS)) {
- // Wellbeing reports that app actions have changed.
- updateWellbeingData();
- } else if (uri.getPath().contains(PATH_MINIMAL_DEVICE)) {
- // Wellbeing reports that minimal device state or config is changed.
- updateLauncherModel(context);
- }
- }
- };
- FeatureFlags.ENABLE_MINIMAL_DEVICE.addChangeListener(mContext, () ->
- updateLauncherModel(context));
-
+ @Override
+ protected void onInitialized(Looper looper) {
+ mWorkerHandler = new Handler(looper);
+ mContentObserver = newContentObserver(mWorkerHandler, this::onWellbeingUriChanged);
if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
- context.registerReceiver(
- new SimpleBroadcastReceiver(this::onWellbeingProviderChanged),
+ mContext.registerReceiver(
+ new SimpleBroadcastReceiver(t -> restartObserver()),
PackageManagerHelper.getPackageFilter(mWellbeingProviderPkg,
Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED,
Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_DATA_CLEARED,
- Intent.ACTION_PACKAGE_RESTARTED));
+ Intent.ACTION_PACKAGE_RESTARTED),
+ null, mWorkerHandler);
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
- context.registerReceiver(new SimpleBroadcastReceiver(this::onAppPackageChanged),
- filter);
+ mContext.registerReceiver(new SimpleBroadcastReceiver(this::onAppPackageChanged),
+ filter, null, mWorkerHandler);
restartObserver();
}
}
+ @WorkerThread
+ private void onWellbeingUriChanged(Uri uri) {
+ Preconditions.assertNonUiThread();
+ if (DEBUG || mIsInTest) {
+ Log.d(TAG, "ContentObserver.onChange() called with: uri = [" + uri + "]");
+ }
+ if (uri.getPath().contains(PATH_ACTIONS)) {
+ // Wellbeing reports that app actions have changed.
+ updateAllPackages();
+ } else if (uri.getPath().contains(PATH_MINIMAL_DEVICE)) {
+ // Wellbeing reports that minimal device state or config is changed.
+ if (!FeatureFlags.ENABLE_MINIMAL_DEVICE.get()) {
+ return;
+ }
+ final Bundle extras = new Bundle();
+ String dbFile;
+ if (isInMinimalDeviceMode()) {
+ dbFile = DB_NAME_MINIMAL_DEVICE;
+ extras.putString(LauncherProvider.KEY_LAYOUT_PROVIDER_AUTHORITY,
+ mWellbeingProviderPkg + ".api");
+ } else {
+ dbFile = InvariantDeviceProfile.INSTANCE.get(mContext).dbFile;
+ }
+ LauncherSettings.Settings.call(mContext.getContentResolver(),
+ LauncherSettings.Settings.METHOD_SWITCH_DATABASE,
+ dbFile, extras);
+ }
+ }
+
public void setInTest(boolean inTest) {
mIsInTest = inTest;
}
- protected void onWellbeingProviderChanged(Intent intent) {
- if (DEBUG || mIsInTest) {
- Log.d(TAG, "Changes to Wellbeing package: intent = [" + intent + "]");
- }
- restartObserver();
- }
-
+ @WorkerThread
private void restartObserver() {
final ContentResolver resolver = mContext.getContentResolver();
resolver.unregisterContentObserver(mContentObserver);
@@ -179,7 +182,7 @@
Log.e(TAG, "Failed to register content observer for " + actionsUri + ": " + e);
if (mIsInTest) throw new RuntimeException(e);
}
- updateWellbeingData();
+ updateAllPackages();
}
@MainThread
@@ -212,39 +215,6 @@
}
}
- private void updateWellbeingData() {
- mWorkerHandler.sendEmptyMessage(MSG_FULL_REFRESH);
- }
-
- private void updateLauncherModel(@NonNull final Context context) {
- if (!FeatureFlags.ENABLE_MINIMAL_DEVICE.get()) {
- reloadLauncherInNormalMode(context);
- return;
- }
- mWorkerHandler.post(() -> {
- if (isInMinimalDeviceMode()) {
- reloadLauncherInMinimalMode(context);
- } else {
- reloadLauncherInNormalMode(context);
- }
- });
- }
-
- private void reloadLauncherInNormalMode(@NonNull final Context context) {
- LauncherSettings.Settings.call(context.getContentResolver(),
- LauncherSettings.Settings.METHOD_SWITCH_DATABASE,
- InvariantDeviceProfile.INSTANCE.get(context).dbFile);
- }
-
- private void reloadLauncherInMinimalMode(@NonNull final Context context) {
- final Bundle extras = new Bundle();
- extras.putString(LauncherProvider.KEY_LAYOUT_PROVIDER_AUTHORITY,
- mWellbeingProviderPkg + ".api");
- LauncherSettings.Settings.call(context.getContentResolver(),
- LauncherSettings.Settings.METHOD_SWITCH_DATABASE,
- DB_NAME_MINIMAL_DEVICE, extras);
- }
-
private Uri.Builder apiBuilder() {
return new Uri.Builder()
.scheme(SCHEME_CONTENT)
@@ -277,7 +247,8 @@
return false;
}
- private boolean updateActions(String... packageNames) {
+ @WorkerThread
+ private boolean updateActions(String[] packageNames) {
if (packageNames.length == 0) {
return true;
}
@@ -340,68 +311,51 @@
return true;
}
- private boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_PACKAGE_REMOVED: {
- String packageName = (String) msg.obj;
- mWorkerHandler.removeCallbacksAndMessages(packageName);
- synchronized (mModelLock) {
- mPackageToActionId.remove(packageName);
- }
- return true;
- }
- case MSG_PACKAGE_ADDED: {
- String packageName = (String) msg.obj;
- mWorkerHandler.removeCallbacksAndMessages(packageName);
- if (!updateActions(packageName)) {
- scheduleRefreshRetry(msg);
- }
- return true;
- }
+ @WorkerThread
+ private void updateActionsWithRetry(int retryCount, @Nullable String packageName) {
+ String[] packageNames = TextUtils.isEmpty(packageName)
+ ? mContext.getSystemService(LauncherApps.class)
+ .getActivityList(null, Process.myUserHandle()).stream()
+ .map(li -> li.getApplicationInfo().packageName).distinct()
+ .toArray(String[]::new)
+ : new String[] { packageName };
- case MSG_FULL_REFRESH: {
- // Remove all existing messages
- mWorkerHandler.removeCallbacksAndMessages(null);
- final String[] packageNames = mContext.getSystemService(LauncherApps.class)
- .getActivityList(null, Process.myUserHandle()).stream()
- .map(li -> li.getApplicationInfo().packageName).distinct()
- .toArray(String[]::new);
- if (!updateActions(packageNames)) {
- scheduleRefreshRetry(msg);
- }
- return true;
- }
+ mWorkerHandler.removeCallbacksAndMessages(packageName);
+ if (updateActions(packageNames)) {
+ return;
}
- return false;
- }
-
- private void scheduleRefreshRetry(Message originalMsg) {
- int retryCount = originalMsg.arg1;
if (retryCount >= RETRY_TIMES_MS.length) {
// To many retries, skip
return;
}
-
- Message msg = Message.obtain(originalMsg);
- msg.arg1 = retryCount + 1;
- mWorkerHandler.sendMessageDelayed(msg, RETRY_TIMES_MS[retryCount]);
+ mWorkerHandler.postDelayed(
+ () -> updateActionsWithRetry(retryCount + 1, packageName),
+ packageName, RETRY_TIMES_MS[retryCount]);
}
+ @WorkerThread
+ private void updateAllPackages() {
+ updateActionsWithRetry(0, null);
+ }
+
+ @WorkerThread
private void onAppPackageChanged(Intent intent) {
if (DEBUG || mIsInTest) Log.d(TAG, "Changes in apps: intent = [" + intent + "]");
- Preconditions.assertUIThread();
+ Preconditions.assertNonUiThread();
final String packageName = intent.getData().getSchemeSpecificPart();
if (packageName == null || packageName.length() == 0) {
// they sent us a bad intent
return;
}
-
final String action = intent.getAction();
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- Message.obtain(mWorkerHandler, MSG_PACKAGE_REMOVED, packageName).sendToTarget();
+ mWorkerHandler.removeCallbacksAndMessages(packageName);
+ synchronized (mModelLock) {
+ mPackageToActionId.remove(packageName);
+ }
} else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- Message.obtain(mWorkerHandler, MSG_PACKAGE_ADDED, packageName).sendToTarget();
+ updateActionsWithRetry(0, packageName);
}
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6774433..1439d4e 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -97,6 +97,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TaskInfoCompat;
@@ -714,6 +715,8 @@
@UiThread
public void onGestureStarted(boolean isLikelyToStartNewTask) {
+ InteractionJankMonitorWrapper.begin(
+ InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */);
notifyGestureStartedAsync();
setIsLikelyToStartNewTask(isLikelyToStartNewTask, false /* animate */);
mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED);
@@ -789,7 +792,8 @@
}
private void onSettledOnEndTarget() {
- switch (mGestureState.getEndTarget()) {
+ final GestureEndTarget endTarget = mGestureState.getEndTarget();
+ switch (endTarget) {
case HOME:
mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT);
// Notify swipe-to-home (recents animation) is finished
@@ -806,7 +810,10 @@
mStateCallback.setState(STATE_RESUME_LAST_TASK);
break;
}
- ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + mGestureState.getEndTarget());
+ ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + endTarget);
+ if (endTarget != NEW_TASK) {
+ InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+ }
}
/** @return Whether this was the task we were waiting to appear, and thus handled it. */
@@ -1130,10 +1137,12 @@
anim.addOnUpdateListener((r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
+ final int cuj = InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME;
anim.addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
+ InteractionJankMonitorWrapper.begin(cuj);
if (mActivity != null) {
removeLiveTileOverlay();
}
@@ -1147,6 +1156,13 @@
// Make sure recents is in its final state
maybeUpdateRecentsAttachedState(false);
mActivityInterface.onSwipeUpToHomeComplete(mDeviceState);
+ InteractionJankMonitorWrapper.end(cuj);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ InteractionJankMonitorWrapper.cancel(cuj);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 0e32c95..2f55f14 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -41,7 +41,10 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAnimationRunner;
+import com.android.launcher3.LauncherAnimationRunner.AnimationResult;
import com.android.launcher3.R;
+import com.android.launcher3.WrappedAnimationRunnerImpl;
+import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -87,6 +90,9 @@
private StateManager<RecentsState> mStateManager;
+ // Strong refs to runners which are cleared when the activity is destroyed
+ private WrappedAnimationRunnerImpl mActivityLaunchAnimationRunner;
+
/**
* Init drag layer and overview panel views.
*/
@@ -169,8 +175,11 @@
}
final TaskView taskView = (TaskView) v;
- RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler,
- true /* startAtFrontOfQueue */) {
+ mActivityLaunchAnimationRunner = new WrappedAnimationRunnerImpl() {
+ @Override
+ public Handler getHandler() {
+ return mUiHandler;
+ }
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
@@ -181,8 +190,10 @@
result.setAnimation(anim, RecentsActivity.this);
}
};
+ final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner<>(
+ mActivityLaunchAnimationRunner, true /* startAtFrontOfQueue */);
return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
- runner, RECENTS_LAUNCH_DURATION,
+ wrapper, RECENTS_LAUNCH_DURATION,
RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY));
}
@@ -287,6 +298,7 @@
protected void onDestroy() {
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
+ mActivityLaunchAnimationRunner = null;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 51f5e5d..798c12b 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -23,6 +23,7 @@
import com.android.launcher3.util.Preconditions;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -149,6 +150,7 @@
mOnFinishedListener.accept(this);
UI_HELPER_EXECUTOR.execute(() -> {
mController.finish(toRecents, sendUserLeaveHint);
+ InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
if (callback != null) {
MAIN_EXECUTOR.execute(callback);
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 4b5adcb..d3c4f55 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -683,7 +683,7 @@
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
gestureState, shouldDefer, this::onConsumerInactive,
- mInputMonitorCompat, disableHorizontalSwipe, factory);
+ mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory);
}
private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) {
@@ -732,6 +732,11 @@
private void reset() {
mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
mGestureState = DEFAULT_STATE;
+ // By default, use batching of the input events, but check receiver before using in the rare
+ // case that the monitor was disposed before the swipe settled
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.setBatchingEnabled(true);
+ }
}
private void preloadOverview(boolean fromInit) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index b1a1133..35dbee9 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -67,6 +67,7 @@
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
import com.android.systemui.shared.system.InputMonitorCompat;
import java.util.function.Consumer;
@@ -92,6 +93,7 @@
private RecentsAnimationCallbacks mActiveCallbacks;
private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
private final InputMonitorCompat mInputMonitorCompat;
+ private final InputEventReceiver mInputEventReceiver;
private final BaseActivityInterface mActivityInterface;
private final AbsSwipeUpHandler.Factory mHandlerFactory;
@@ -135,8 +137,8 @@
public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
boolean isDeferredDownTarget, Consumer<OtherActivityInputConsumer> onCompleteCallback,
- InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe,
- Factory handlerFactory) {
+ InputMonitorCompat inputMonitorCompat, InputEventReceiver inputEventReceiver,
+ boolean disableHorizontalSwipe, Factory handlerFactory) {
super(base);
mDeviceState = deviceState;
mNavBarPosition = mDeviceState.getNavBarPosition();
@@ -154,6 +156,7 @@
mOnCompleteCallback = onCompleteCallback;
mVelocityTracker = VelocityTracker.obtain();
mInputMonitorCompat = inputMonitorCompat;
+ mInputEventReceiver = inputEventReceiver;
boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning();
mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
@@ -215,6 +218,9 @@
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
+ // Until we detect the gesture, handle events as we receive them
+ mInputEventReceiver.setBatchingEnabled(false);
+
Object traceToken = TraceHelper.INSTANCE.beginSection(DOWN_EVT,
FLAG_CHECK_FOR_RACE_CONDITIONS);
mActivePointerId = ev.getPointerId(0);
@@ -351,6 +357,8 @@
}
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
mInputMonitorCompat.pilferPointers();
+ // Once we detect the gesture, we can enable batching to reduce further updates
+ mInputEventReceiver.setBatchingEnabled(true);
mActivityInterface.closeOverlay();
ActivityManagerWrapper.getInstance().closeSystemWindows(
diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
index 70181fb..16886ec 100644
--- a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
@@ -24,7 +24,7 @@
/** Shows the Home gesture interactive tutorial. */
public class AssistantGestureTutorialFragment extends TutorialFragment {
@Override
- int getHandAnimationResId() {
+ Integer getHandAnimationResId() {
return R.drawable.assistant_gesture;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
index bef50ea..41db684 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
@@ -24,7 +24,7 @@
/** Shows the Back gesture interactive tutorial. */
public class BackGestureTutorialFragment extends TutorialFragment {
@Override
- int getHandAnimationResId() {
+ Integer getHandAnimationResId() {
return R.drawable.back_gesture;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
index e2a9d12..63595a5 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
@@ -21,7 +21,7 @@
/** Shows the Home gesture interactive tutorial. */
public class HomeGestureTutorialFragment extends TutorialFragment {
@Override
- int getHandAnimationResId() {
+ Integer getHandAnimationResId() {
return R.drawable.home_gesture;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
index 3357b70..93200bb 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
@@ -21,7 +21,7 @@
/** Shows the Overview gesture interactive tutorial. */
public class OverviewGestureTutorialFragment extends TutorialFragment {
@Override
- int getHandAnimationResId() {
+ Integer getHandAnimationResId() {
return R.drawable.overview_gesture;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java
new file mode 100644
index 0000000..d54efc5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java
@@ -0,0 +1,102 @@
+/*
+ * 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.quickstep.interaction;
+
+import android.graphics.PointF;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
+import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
+
+/** A {@link TutorialController} for the Sandbox Mode. */
+public class SandboxModeTutorialController extends SwipeUpGestureTutorialController {
+
+ SandboxModeTutorialController(SandboxModeTutorialFragment fragment, TutorialType tutorialType) {
+ super(fragment, tutorialType);
+ }
+
+ @Nullable
+ @Override
+ Integer getTitleStringId() {
+ return R.string.sandbox_mode_title;
+ }
+
+ @Nullable
+ @Override
+ Integer getSubtitleStringId() {
+ return R.string.sandbox_mode_subtitle;
+ }
+
+ @Nullable
+ @Override
+ Integer getActionButtonStringId() {
+ return R.string.gesture_tutorial_action_button_label_done;
+ }
+
+ @Override
+ void onActionButtonClicked(View button) {
+ mTutorialFragment.closeTutorial();
+ }
+
+ @Override
+ public void onBackGestureAttempted(BackGestureResult result) {
+ switch (result) {
+ case BACK_COMPLETED_FROM_LEFT:
+ case BACK_COMPLETED_FROM_RIGHT:
+ showRippleEffect(null);
+ showFeedback(R.string.sandbox_mode_back_gesture_feedback_successful);
+ break;
+ case BACK_CANCELLED_FROM_RIGHT:
+ showFeedback(R.string.back_gesture_feedback_cancelled_right_edge);
+ break;
+ case BACK_CANCELLED_FROM_LEFT:
+ showFeedback(R.string.back_gesture_feedback_cancelled_left_edge);
+ break;
+ case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ showFeedback(R.string.sandbox_mode_back_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ }
+ }
+
+ @Override
+ public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
+ switch (result) {
+ case ASSISTANT_COMPLETED:
+ showRippleEffect(null);
+ showFeedback(R.string.sandbox_mode_assistant_gesture_feedback_successful);
+ break;
+ case HOME_GESTURE_COMPLETED:
+ animateFakeTaskViewHome(finalVelocity, () -> {
+ showFeedback(R.string.sandbox_mode_home_gesture_feedback_successful);
+ });
+ break;
+ case OVERVIEW_GESTURE_COMPLETED:
+ fadeOutFakeTaskView(true, () -> {
+ showFeedback(R.string.sandbox_mode_overview_gesture_feedback_successful);
+ });
+ break;
+ case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
+ case HOME_OR_OVERVIEW_CANCELLED:
+ case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java
new file mode 100644
index 0000000..955a2f7
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java
@@ -0,0 +1,43 @@
+/*
+ * 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.quickstep.interaction;
+
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.quickstep.interaction.TutorialController.TutorialType;
+
+/** Shows the general navigation gesture sandbox environment. */
+public class SandboxModeTutorialFragment extends TutorialFragment {
+
+ @Override
+ TutorialController createController(TutorialType type) {
+ return new SandboxModeTutorialController(this, type);
+ }
+
+ @Override
+ Class<? extends TutorialController> getControllerClass() {
+ return SandboxModeTutorialController.class;
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN && mTutorialController != null) {
+ mTutorialController.setRippleHotspot(motionEvent.getX(), motionEvent.getY());
+ }
+ return super.onTouch(view, motionEvent);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index db80342..2198ade 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -52,7 +52,7 @@
final View mFakeTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
- final TutorialHandAnimation mHandCoachingAnimation;
+ @Nullable final TutorialHandAnimation mHandCoachingAnimation;
final ImageView mHandCoachingView;
final Button mActionTextButton;
final Button mActionButton;
@@ -145,13 +145,16 @@
void onActionTextButtonClicked(View button) {}
void showHandCoachingAnimation() {
- if (isComplete()) {
+ if (isComplete() || mHandCoachingAnimation == null) {
return;
}
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
}
void hideHandCoachingAnimation() {
+ if (mHandCoachingAnimation == null) {
+ return;
+ }
mHandCoachingAnimation.stop();
mHandCoachingView.setVisibility(View.INVISIBLE);
}
@@ -210,7 +213,8 @@
return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE
|| mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE
|| mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE
- || mTutorialType == TutorialType.ASSISTANT_COMPLETE;
+ || mTutorialType == TutorialType.ASSISTANT_COMPLETE
+ || mTutorialType == TutorialType.SANDBOX_MODE;
}
/** Denotes the type of the tutorial. */
@@ -223,6 +227,7 @@
OVERVIEW_NAVIGATION,
OVERVIEW_NAVIGATION_COMPLETE,
ASSISTANT,
- ASSISTANT_COMPLETE
+ ASSISTANT_COMPLETE,
+ SANDBOX_MODE
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index c90ad94..f297d5a 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -43,7 +43,7 @@
TutorialType mTutorialType;
@Nullable TutorialController mTutorialController = null;
View mRootView;
- TutorialHandAnimation mHandCoachingAnimation;
+ @Nullable TutorialHandAnimation mHandCoachingAnimation = null;
EdgeBackGestureHandler mEdgeBackGestureHandler;
NavBarGestureHandler mNavBarGestureHandler;
private View mLauncherView;
@@ -76,13 +76,17 @@
case ASSISTANT:
case ASSISTANT_COMPLETE:
return new AssistantGestureTutorialFragment();
+ case SANDBOX_MODE:
+ return new SandboxModeTutorialFragment();
default:
Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name());
}
return null;
}
- abstract int getHandAnimationResId();
+ @Nullable Integer getHandAnimationResId() {
+ return null;
+ }
abstract TutorialController createController(TutorialType type);
@@ -116,8 +120,11 @@
return insets;
});
mRootView.setOnTouchListener(this);
- mHandCoachingAnimation =
- new TutorialHandAnimation(getContext(), mRootView, getHandAnimationResId());
+ Integer handAnimationResId = getHandAnimationResId();
+ if (handAnimationResId != null) {
+ mHandCoachingAnimation =
+ new TutorialHandAnimation(getContext(), mRootView, handAnimationResId);
+ }
InvariantDeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(getContext());
mLauncherView = new SandboxLauncherRenderer(getContext(), dp, true).getRenderedView();
((ViewGroup) mRootView).addView(mLauncherView, 0);
@@ -133,7 +140,10 @@
@Override
public void onPause() {
super.onPause();
- mHandCoachingAnimation.stop();
+
+ if (mHandCoachingAnimation != null) {
+ mHandCoachingAnimation.stop();
+ }
}
@Override
@@ -183,7 +193,7 @@
return mLauncherView;
}
- TutorialHandAnimation getHandAnimation() {
+ @Nullable TutorialHandAnimation getHandAnimation() {
return mHandCoachingAnimation;
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index de44e07..5f0ef83 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -23,6 +23,7 @@
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import static com.android.launcher3.Utilities.newContentObserver;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -73,12 +74,9 @@
private static final boolean DEBUG = false;
private static final String DELIMITER_DOT = "\\.";
- private ContentObserver mSystemAutoRotateObserver = new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- updateAutoRotateSetting();
- }
- };
+ private ContentObserver mSystemAutoRotateObserver =
+ newContentObserver(new Handler(), t -> updateAutoRotateSetting());
+
@Retention(SOURCE)
@IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
public @interface SurfaceRotation {}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
index 04308c8..19c6588 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -21,6 +21,8 @@
import android.os.Handler;
import com.android.launcher3.LauncherAnimationRunner;
+import com.android.launcher3.LauncherAnimationRunner.AnimationResult;
+import com.android.launcher3.WrappedAnimationRunnerImpl;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -28,14 +30,17 @@
public abstract class RemoteAnimationProvider {
- LauncherAnimationRunner mAnimationRunner;
+ WrappedAnimationRunnerImpl mAnimationRunner;
public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets);
ActivityOptions toActivityOptions(Handler handler, long duration, Context context) {
- mAnimationRunner = new LauncherAnimationRunner(handler,
- false /* startAtFrontOfQueue */) {
+ mAnimationRunner = new WrappedAnimationRunnerImpl() {
+ @Override
+ public Handler getHandler() {
+ return handler;
+ }
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
@@ -45,7 +50,6 @@
};
final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner(
mAnimationRunner, false /* startAtFrontOfQueue */);
-
return ActivityOptionsCompat.makeRemoteAnimation(
new RemoteAnimationAdapterCompat(wrapper, duration, 0));
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4bfa4da..7a8e11d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2161,7 +2161,12 @@
tv.notifyTaskLaunchFailed(TAG);
}
};
- tv.launchTask(false, onLaunchResult, getHandler());
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ finishRecentsAnimation(false /* toRecents */, null);
+ onLaunchResult.accept(true /* success */);
+ } else {
+ tv.launchTask(false, onLaunchResult, getHandler());
+ }
Task task = tv.getTask();
if (task != null) {
mActivity.getStatsLogManager().logger().withItemInfo(tv.getItemInfo())
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 8fbf44b..686f878 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -217,6 +217,7 @@
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (isRunningTask()) {
+ // TODO: Replace this animation with createRecentsWindowAnimator
createLaunchAnimationForRunningTask().start();
} else {
launchTask(true /* animate */);
@@ -364,10 +365,7 @@
final PendingAnimation pendingAnimation = getRecentsView().createTaskLaunchAnimation(
this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR);
AnimatorPlaybackController currentAnimation = pendingAnimation.createPlaybackController();
- currentAnimation.setEndAction(() -> {
- pendingAnimation.finish(true);
- launchTask(false);
- });
+ currentAnimation.setEndAction(() -> pendingAnimation.finish(true));
return currentAnimation;
}
@@ -390,20 +388,6 @@
public void launchTask(boolean animate, boolean freezeTaskList, Consumer<Boolean> resultCallback,
Handler resultCallbackHandler) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- if (isRunningTask()) {
- getRecentsView().finishRecentsAnimation(false /* toRecents */,
- () -> resultCallbackHandler.post(() -> resultCallback.accept(true)));
- } else {
- launchTaskInternal(animate, freezeTaskList, resultCallback, resultCallbackHandler);
- }
- } else {
- launchTaskInternal(animate, freezeTaskList, resultCallback, resultCallbackHandler);
- }
- }
-
- private void launchTaskInternal(boolean animate, boolean freezeTaskList,
- Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
if (mTask != null) {
final ActivityOptions opts;
TestLogging.recordEvent(
diff --git a/res/layout/search_result_suggest.xml b/res/layout/search_result_suggest.xml
new file mode 100644
index 0000000..c5d96f0
--- /dev/null
+++ b/res/layout/search_result_suggest.xml
@@ -0,0 +1,38 @@
+<?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.SearchResultSuggestRow xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/TextHeadline"
+ android:id="@+id/section_title"
+ android:background="?android:attr/selectableItemBackground"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:padding="4dp"
+ android:minHeight="48dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="14sp">
+
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="8dp"
+ android:layout_marginBottom="4dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="14sp" />
+
+</com.android.launcher3.views.SearchResultSuggestRow>
\ No newline at end of file
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 43ccb79..1e023df 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -34,6 +34,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
@@ -44,6 +45,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
+import android.net.Uri;
import android.os.Build;
import android.os.DeadObjectException;
import android.os.Handler;
@@ -83,6 +85,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
+import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -661,6 +664,18 @@
return slop * slop;
}
+ /**
+ * Helper method to create a content provider
+ */
+ public static ContentObserver newContentObserver(Handler handler, Consumer<Uri> command) {
+ return new ContentObserver(handler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ command.accept(uri);
+ }
+ };
+ }
+
private static class FixedSizeEmptyDrawable extends ColorDrawable {
private final int mSize;
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 81d94ba..8bc8e53 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -98,6 +98,8 @@
public static final int VIEW_TYPE_SEARCH_THUMBNAIL = 1 << 12;
+ public static final int VIEW_TYPE_SEARCH_SUGGEST = 1 << 13;
+
// 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;
@@ -189,7 +191,8 @@
|| viewType == VIEW_TYPE_SEARCH_ROW
|| viewType == VIEW_TYPE_SEARCH_PEOPLE
|| viewType == VIEW_TYPE_SEARCH_THUMBNAIL
- || viewType == VIEW_TYPE_SEARCH_ICON_ROW;
+ || viewType == VIEW_TYPE_SEARCH_ICON_ROW
+ || viewType == VIEW_TYPE_SEARCH_SUGGEST;
}
}
@@ -467,6 +470,9 @@
case VIEW_TYPE_SEARCH_THUMBNAIL:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_thumbnail, parent, false));
+ case VIEW_TYPE_SEARCH_SUGGEST:
+ return new ViewHolder(mLayoutInflater.inflate(
+ R.layout.search_result_suggest, parent, false));
default:
throw new RuntimeException("Unexpected view type");
}
@@ -554,6 +560,7 @@
case VIEW_TYPE_SEARCH_ICON_ROW:
case VIEW_TYPE_SEARCH_PEOPLE:
case VIEW_TYPE_SEARCH_THUMBNAIL:
+ case VIEW_TYPE_SEARCH_SUGGEST:
AdapterItemWithPayload item =
(AdapterItemWithPayload) mApps.getAdapterItems().get(position);
PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 42e247a..77d2b85 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -53,8 +53,8 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.PinRequestHelper;
-import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -87,7 +87,6 @@
private Bundle mWidgetOptions;
private boolean mFinishOnPause = false;
- private InstantAppResolver mInstantAppResolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -101,7 +100,6 @@
mApp = LauncherAppState.getInstance(this);
mIdp = mApp.getInvariantDeviceProfile();
- mInstantAppResolver = InstantAppResolver.newInstance(this);
// Use the application context to get the device profile, as in multiwindow-mode, the
// confirmation activity might be rotated.
@@ -322,6 +320,8 @@
}
private void logCommand(StatsLogManager.EventEnum command) {
- getStatsLogManager().logger().log(command);
+ getStatsLogManager().logger()
+ .withItemInfo((ItemInfo) mWidgetCell.getWidgetView().getTag())
+ .log(command);
}
}
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index e03fd72..b11b419 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_TASK;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.CONTAINER_NOT_SET;
+import static com.android.launcher3.shortcuts.ShortcutKey.EXTRA_SHORTCUT_ID;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -50,10 +51,10 @@
import com.android.launcher3.logger.LauncherAtom.PredictionContainer;
import com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
+import com.android.launcher3.logger.LauncherAtom.Shortcut;
import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
import com.android.launcher3.model.ModelWriter;
-import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ContentWriter;
import java.util.Optional;
@@ -282,9 +283,14 @@
case ITEM_TYPE_DEEP_SHORTCUT:
itemBuilder
.setShortcut(nullableComponent
- .map(component -> LauncherAtom.Shortcut.newBuilder()
- .setShortcutName(component.flattenToShortString())
- .setShortcutId(ShortcutKey.fromItemInfo(this).getId()))
+ .map(component -> {
+ Shortcut.Builder lsb = Shortcut.newBuilder()
+ .setShortcutName(component.flattenToShortString());
+ Optional.ofNullable(getIntent())
+ .map(i -> i.getStringExtra(EXTRA_SHORTCUT_ID))
+ .ifPresent(lsb::setShortcutId);
+ return lsb;
+ })
.orElse(LauncherAtom.Shortcut.newBuilder()));
break;
case ITEM_TYPE_SHORTCUT:
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index d5b32fc..90285c4 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -151,32 +151,52 @@
* @param viewsToFlip number of views from the top to to flip in case of reverse order
*/
protected void reorderAndShow(int viewsToFlip) {
+ setupForDisplay();
+ boolean reverseOrder = mIsAboveIcon;
+ if (reverseOrder) {
+ reverseOrder(viewsToFlip);
+ }
+ onInflationComplete(reverseOrder);
+ addArrow();
+ animateOpen();
+ }
+
+ /**
+ * Shows the popup at the desired location.
+ */
+ protected void show() {
+ setupForDisplay();
+ onInflationComplete(false);
+ addArrow();
+ animateOpen();
+ }
+
+ private void setupForDisplay() {
setVisibility(View.INVISIBLE);
mIsOpen = true;
getPopupContainer().addView(this);
orientAboutObject();
+ }
- boolean reverseOrder = mIsAboveIcon;
- if (reverseOrder) {
- int count = getChildCount();
- ArrayList<View> allViews = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- if (i == viewsToFlip) {
- Collections.reverse(allViews);
- }
- allViews.add(getChildAt(i));
+ private void reverseOrder(int viewsToFlip) {
+ int count = getChildCount();
+ ArrayList<View> allViews = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ if (i == viewsToFlip) {
+ Collections.reverse(allViews);
}
- Collections.reverse(allViews);
- removeAllViews();
- for (int i = 0; i < count; i++) {
- addView(allViews.get(i));
- }
-
- orientAboutObject();
+ allViews.add(getChildAt(i));
}
- onInflationComplete(reverseOrder);
+ Collections.reverse(allViews);
+ removeAllViews();
+ for (int i = 0; i < count; i++) {
+ addView(allViews.get(i));
+ }
- // Add the arrow.
+ orientAboutObject();
+ }
+
+ private void addArrow() {
final Resources res = getResources();
final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
? R.dimen.popup_arrow_horizontal_center_start
@@ -214,8 +234,6 @@
mArrow.setPivotX(arrowLp.width / 2);
mArrow.setPivotY(mIsAboveIcon ? arrowLp.height : 0);
-
- animateOpen();
}
protected boolean isAlignedWithStart() {
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index 4baecb7..f4b059d 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -306,6 +306,15 @@
return true;
});
sandboxCategory.addPreference(launchAssistantTutorialPreference);
+ Preference launchSandboxModeTutorialPreference = new Preference(context);
+ launchSandboxModeTutorialPreference.setKey("launchSandboxMode");
+ launchSandboxModeTutorialPreference.setTitle("Launch Sandbox Mode");
+ launchSandboxModeTutorialPreference.setSummary("Practice navigation gestures");
+ launchSandboxModeTutorialPreference.setOnPreferenceClickListener(preference -> {
+ startActivity(launchSandboxIntent.putExtra("tutorial_type", "SANDBOX_MODE"));
+ return true;
+ });
+ sandboxCategory.addPreference(launchSandboxModeTutorialPreference);
}
private String toName(String action) {
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 5a60f53..ecf4f36 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -21,14 +21,9 @@
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
import android.app.Activity;
-import android.content.ContentResolver;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.provider.Settings;
-import android.util.Log;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -43,16 +38,6 @@
public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
- private final ContentResolver mContentResolver;
- private boolean mSystemAutoRotateEnabled;
-
- private ContentObserver mSystemAutoRotateObserver = new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- updateAutoRotateSetting();
- }
- };
-
public static boolean getAllowRotationDefaultValue() {
// If the device's pixel density was scaled (usually via settings for A11y), use the
// original dimensions to determine if rotation is allowed of not.
@@ -106,20 +91,6 @@
} else {
mSharedPrefs = null;
}
-
- mContentResolver = activity.getContentResolver();
- }
-
- private void updateAutoRotateSetting() {
- int autoRotateEnabled = 0;
- try {
- autoRotateEnabled = Settings.System.getInt(mContentResolver,
- Settings.System.ACCELEROMETER_ROTATION);
- } catch (Settings.SettingNotFoundException e) {
- Log.e(TAG, "autorotate setting not found", e);
- }
-
- mSystemAutoRotateEnabled = autoRotateEnabled == 1;
}
@Override
@@ -129,7 +100,6 @@
getAllowRotationDefaultValue());
if (mHomeRotationEnabled != wasRotationEnabled) {
notifyChange();
- updateAutoRotateSetting();
}
}
@@ -165,11 +135,6 @@
if (!mInitialized) {
mInitialized = true;
notifyChange();
-
- mContentResolver.registerContentObserver(
- Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
- false, mSystemAutoRotateObserver);
- updateAutoRotateSetting();
}
}
@@ -179,7 +144,6 @@
if (mSharedPrefs != null) {
mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
}
- mContentResolver.unregisterContentObserver(mSystemAutoRotateObserver);
}
}
@@ -225,9 +189,8 @@
@Override
public String toString() {
return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d,"
- + " mLastActivityFlags=%d, mIgnoreAutoRotateSettings=%b, mHomeRotationEnabled=%b,"
- + " mSystemAutoRotateEnabled=%b]",
+ + " mLastActivityFlags=%d, mIgnoreAutoRotateSettings=%b, mHomeRotationEnabled=%b]",
mStateHandlerRequest, mCurrentStateRequest, mLastActivityFlags,
- mIgnoreAutoRotateSettings, mHomeRotationEnabled, mSystemAutoRotateEnabled);
+ mIgnoreAutoRotateSettings, mHomeRotationEnabled);
}
}
diff --git a/src/com/android/launcher3/util/BgObjectWithLooper.java b/src/com/android/launcher3/util/BgObjectWithLooper.java
new file mode 100644
index 0000000..1483c43
--- /dev/null
+++ b/src/com/android/launcher3/util/BgObjectWithLooper.java
@@ -0,0 +1,46 @@
+/*
+ * 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.util;
+
+import android.os.Looper;
+
+import androidx.annotation.WorkerThread;
+
+/**
+ * Utility class to define an object which does most of it's processing on a
+ * dedicated background thread.
+ */
+public abstract class BgObjectWithLooper {
+
+ /**
+ * Start initialization of the object
+ */
+ public final void initializeInBackground(String threadName) {
+ new Thread(this::runOnThread, threadName).start();
+ }
+
+ private void runOnThread() {
+ Looper.prepare();
+ onInitialized(Looper.myLooper());
+ Looper.loop();
+ }
+
+ /**
+ * Called on the background thread to handle initialization
+ */
+ @WorkerThread
+ protected abstract void onInitialized(Looper looper);
+}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 52a82f8..d9a14e9 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.views;
-import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.Utilities.getBadge;
import static com.android.launcher3.Utilities.getFullDrawable;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
@@ -23,9 +22,6 @@
import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
@@ -74,7 +70,6 @@
private static @Nullable IconLoadResult sIconLoadResult;
public static final float SHAPE_PROGRESS_DURATION = 0.10f;
- private static final int FADE_DURATION_MS = 200;
private static final RectF sTmpRectF = new RectF();
private static final Object[] sTmpObjArray = new Object[1];
@@ -89,6 +84,9 @@
private IconLoadResult mIconLoadResult;
+ // Draw the drawable of the BubbleTextView behind ClipIconView to reveal the built in shadow.
+ private View mBtvDrawable;
+
private ClipIconView mClipIconView;
private @Nullable Drawable mBadge;
@@ -98,7 +96,6 @@
private final Rect mFinalDrawableBounds = new Rect();
- private AnimatorSet mFadeAnimatorSet;
private ListenerView mListenerView;
private Runnable mFastFinishRunnable;
@@ -116,6 +113,8 @@
mIsRtl = Utilities.isRtl(getResources());
mListenerView = new ListenerView(context, attrs);
mClipIconView = new ClipIconView(context, attrs);
+ mBtvDrawable = new ImageView(context, attrs);
+ addView(mBtvDrawable);
addView(mClipIconView);
setWillNotDraw(false);
}
@@ -176,6 +175,7 @@
setLayoutParams(lp);
mClipIconView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
+ mBtvDrawable.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
}
private void updatePosition(RectF pos, InsettableFrameLayout.LayoutParams lp) {
@@ -292,6 +292,8 @@
drawable = drawable == null ? null : drawable.getConstantState().newDrawable();
int iconOffset = getOffsetForIconBounds(l, drawable, pos);
synchronized (iconLoadResult) {
+ iconLoadResult.btvDrawable = btvIcon == null || drawable == btvIcon
+ ? null : btvIcon.getConstantState().newDrawable();
iconLoadResult.drawable = drawable;
iconLoadResult.badge = badge;
iconLoadResult.iconOffset = iconOffset;
@@ -311,7 +313,8 @@
* @param iconOffset The amount of offset needed to match this view with the original view.
*/
@UiThread
- private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge, int iconOffset) {
+ private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge,
+ @Nullable Drawable btvIcon, int iconOffset) {
final InsettableFrameLayout.LayoutParams lp =
(InsettableFrameLayout.LayoutParams) getLayoutParams();
mBadge = badge;
@@ -342,6 +345,10 @@
mBadge.setBounds(0, 0, clipViewOgWidth, clipViewOgHeight);
}
}
+
+ if (!mIsOpening && btvIcon != null) {
+ mBtvDrawable.setBackground(btvIcon);
+ }
invalidate();
}
@@ -360,7 +367,7 @@
synchronized (mIconLoadResult) {
if (mIconLoadResult.isIconLoaded) {
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
- mIconLoadResult.iconOffset);
+ mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
setIconAndDotVisible(originalView, false);
} else {
mIconLoadResult.onIconLoaded = () -> {
@@ -369,7 +376,7 @@
}
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
- mIconLoadResult.iconOffset);
+ mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
setVisibility(VISIBLE);
setIconAndDotVisible(originalView, false);
@@ -434,10 +441,6 @@
mEndRunnable.run();
mEndRunnable = null;
}
- if (mFadeAnimatorSet != null) {
- mFadeAnimatorSet.end();
- mFadeAnimatorSet = null;
- }
}
@Override
@@ -546,8 +549,16 @@
setIconAndDotVisible(originalView, true);
view.finish(dragLayer);
} else {
- view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
- view.mFadeAnimatorSet.start();
+ originalView.setVisibility(VISIBLE);
+ if (originalView instanceof IconLabelDotView) {
+ setIconAndDotVisible(originalView, true);
+ }
+ if (originalView instanceof BubbleTextView) {
+ BubbleTextView btv = (BubbleTextView) originalView;
+ btv.setIconVisible(true);
+ btv.setForceHideDot(true);
+ }
+ view.finish(dragLayer);
}
} else {
view.finish(dragLayer);
@@ -564,47 +575,6 @@
return view;
}
- private AnimatorSet createFadeAnimation(View originalView, DragLayer dragLayer) {
- AnimatorSet fade = new AnimatorSet();
- fade.setDuration(FADE_DURATION_MS);
- fade.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- originalView.setVisibility(VISIBLE);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- finish(dragLayer);
- }
- });
-
- if (originalView instanceof IconLabelDotView) {
- fade.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- setIconAndDotVisible(originalView, true);
- }
- });
- }
-
- if (originalView instanceof BubbleTextView) {
- BubbleTextView btv = (BubbleTextView) originalView;
- fade.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- btv.setIconVisible(true);
- btv.setForceHideDot(true);
- }
- });
- fade.play(ObjectAnimator.ofInt(btv.getIcon(), DRAWABLE_ALPHA, 0, 255));
- } else if (!(originalView instanceof FolderIcon)) {
- fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f));
- }
-
- return fade;
- }
-
private void finish(DragLayer dragLayer) {
((ViewGroup) dragLayer.getParent()).removeView(this);
dragLayer.removeView(mListenerView);
@@ -628,11 +598,7 @@
mLoadIconSignal = null;
mEndRunnable = null;
mFinalDrawableBounds.setEmpty();
- if (mFadeAnimatorSet != null) {
- mFadeAnimatorSet.cancel();
- }
mPositionOut = null;
- mFadeAnimatorSet = null;
mListenerView.setListener(null);
mOriginalIcon = null;
mOnTargetChangeRunnable = null;
@@ -640,11 +606,13 @@
sTmpObjArray[0] = null;
mIconLoadResult = null;
mClipIconView.recycle();
+ mBtvDrawable.setBackground(null);
mFastFinishRunnable = null;
}
private static class IconLoadResult {
final ItemInfo itemInfo;
+ Drawable btvDrawable;
Drawable drawable;
Drawable badge;
int iconOffset;
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index a8caa9e..80f0981 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -133,7 +133,7 @@
view.setOnLongClickListener(popup);
popup.mItemMap.put(view, item);
}
- popup.reorderAndShow(popup.getChildCount());
+ popup.show();
}
@VisibleForTesting
diff --git a/src/com/android/launcher3/views/SearchResultIconRow.java b/src/com/android/launcher3/views/SearchResultIconRow.java
index 57c85cf..6438d1d 100644
--- a/src/com/android/launcher3/views/SearchResultIconRow.java
+++ b/src/com/android/launcher3/views/SearchResultIconRow.java
@@ -34,6 +34,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -42,6 +43,7 @@
import com.android.launcher3.touch.ItemClickHandler;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTarget.ItemType;
import com.android.systemui.plugins.shared.SearchTargetEvent;
/**
@@ -82,7 +84,8 @@
if (payload.mRemoteAction != null) {
prepareUsingRemoteAction(payload.mRemoteAction,
payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
- payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
+ payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START),
+ payload.type == ItemType.ACTION);
} else {
prepareUsingShortcutInfo(payload.shortcuts.get(0));
}
@@ -101,7 +104,8 @@
});
}
- private void prepareUsingRemoteAction(RemoteAction remoteAction, String token, boolean start) {
+ private void prepareUsingRemoteAction(RemoteAction remoteAction, String token, boolean start,
+ boolean useIconToBadge) {
RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(remoteAction, token, start);
applyFromRemoteActionInfo(itemInfo);
@@ -109,8 +113,17 @@
// If the Drawable from the remote action is not AdaptiveBitmap, styling will not work.
try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
Drawable d = itemInfo.getRemoteAction().getIcon().loadDrawable(getContext());
- itemInfo.bitmap = li.createBadgedIconBitmap(d, itemInfo.user,
+ BitmapInfo bitmap = li.createBadgedIconBitmap(d, itemInfo.user,
Build.VERSION.SDK_INT);
+
+ if (useIconToBadge) {
+ BitmapInfo placeholder = li.createIconBitmap(
+ itemInfo.getRemoteAction().getTitle().toString().substring(0, 1),
+ bitmap.color);
+ itemInfo.bitmap = li.badgeBitmap(placeholder.icon, bitmap);
+ } else {
+ itemInfo.bitmap = bitmap;
+ }
reapplyItemInfoAsync(itemInfo);
}
});
@@ -138,7 +151,7 @@
} else {
RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
- searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.REMOTE_ACTION,
+ searchTargetEvent = getSearchTargetEvent(ItemType.ACTION,
eventType);
searchTargetEvent.bundle = new Bundle();
searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction();
diff --git a/src/com/android/launcher3/views/SearchResultPeopleView.java b/src/com/android/launcher3/views/SearchResultPeopleView.java
index eacc095..0c9a22f 100644
--- a/src/com/android/launcher3/views/SearchResultPeopleView.java
+++ b/src/com/android/launcher3/views/SearchResultPeopleView.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.views;
-import static android.content.Intent.URI_ALLOW_UNSAFE;
-import static android.content.Intent.URI_ANDROID_APP_SCHEME;
-
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -28,7 +25,6 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
@@ -50,7 +46,6 @@
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
-import java.net.URISyntaxException;
import java.util.ArrayList;
/**
@@ -66,7 +61,7 @@
private TextView mTitleView;
private ImageButton[] mProviderButtons = new ImageButton[3];
private AllAppsSearchPlugin mPlugin;
- private Uri mContactUri;
+ private Intent mIntent;
private final Object[] mTargetInfo = createTargetInfo();
public SearchResultPeopleView(Context context) {
@@ -109,7 +104,7 @@
Bundle payload = adapterItemWithPayload.getPayload();
mPlugin = adapterItemWithPayload.getPlugin();
mTitleView.setText(payload.getString("title"));
- mContactUri = payload.getParcelable("contact_uri");
+ mIntent = payload.getParcelable("intent");
Bitmap icon = payload.getParcelable("icon");
if (icon != null) {
RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
@@ -125,25 +120,20 @@
for (int i = 0; i < mProviderButtons.length; i++) {
ImageButton button = mProviderButtons[i];
if (providers != null && i < providers.size()) {
- try {
- Bundle provider = providers.get(i);
- Intent intent = Intent.parseUri(provider.getString("intent_uri_str"),
- URI_ANDROID_APP_SCHEME | URI_ALLOW_UNSAFE);
- setupProviderButton(button, provider, intent, adapterItemWithPayload);
- String pkg = provider.getString("package_name");
- UI_HELPER_EXECUTOR.post(() -> {
- try {
- ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
- pkg, 0);
- Drawable appIcon = applicationInfo.loadIcon(mPackageManager);
- MAIN_EXECUTOR.post(() -> button.setImageDrawable(appIcon));
- } catch (PackageManager.NameNotFoundException ignored) {
- }
+ Bundle provider = providers.get(i);
+ Intent intent = provider.getParcelable("intent");
+ setupProviderButton(button, provider, intent, adapterItemWithPayload);
+ String pkg = provider.getString("package_name");
+ UI_HELPER_EXECUTOR.post(() -> {
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
+ pkg, 0);
+ Drawable appIcon = applicationInfo.loadIcon(mPackageManager);
+ MAIN_EXECUTOR.post(() -> button.setImageDrawable(appIcon));
+ } catch (PackageManager.NameNotFoundException ignored) {
+ }
- });
- } catch (URISyntaxException ex) {
- button.setVisibility(GONE);
- }
+ });
} else {
button.setVisibility(GONE);
}
@@ -165,7 +155,7 @@
SearchTarget.ItemType.PEOPLE,
SearchTargetEvent.CHILD_SELECT);
searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri);
+ searchTargetEvent.bundle.putParcelable("intent", mIntent);
searchTargetEvent.bundle.putBundle("provider", provider);
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
@@ -175,14 +165,13 @@
private void handleSelection(int eventType) {
- if (mContactUri != null) {
+ if (mIntent != null) {
Launcher launcher = Launcher.getLauncher(getContext());
- launcher.startActivitySafely(this, new Intent(Intent.ACTION_VIEW, mContactUri).setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK), null);
+ launcher.startActivitySafely(this, mIntent, null);
SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.PEOPLE,
eventType);
searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri);
+ searchTargetEvent.bundle.putParcelable("intent", mIntent);
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
}
diff --git a/src/com/android/launcher3/views/SearchResultSuggestRow.java b/src/com/android/launcher3/views/SearchResultSuggestRow.java
new file mode 100644
index 0000000..6543c76
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchResultSuggestRow.java
@@ -0,0 +1,132 @@
+/*
+ * 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 static com.android.systemui.plugins.shared.SearchTarget.ItemType.SUGGEST;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.RemoteActionItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+/**
+ * A view representing a fallback search suggestion row.
+ */
+public class SearchResultSuggestRow extends LinearLayout implements
+ View.OnClickListener, AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
+
+ private final Object[] mTargetInfo = createTargetInfo();
+ private AllAppsSearchPlugin mPlugin;
+ private AdapterItemWithPayload<SearchTarget> mAdapterItem;
+ private TextView mTitle;
+
+
+ public SearchResultSuggestRow(@NonNull Context context) {
+ super(context);
+ }
+
+ public SearchResultSuggestRow(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SearchResultSuggestRow(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTitle = findViewById(R.id.title);
+ setOnClickListener(this);
+ }
+ @Override
+ public void applyAdapterInfo(AdapterItemWithPayload<SearchTarget> adapterItemWithPayload) {
+ mAdapterItem = adapterItemWithPayload;
+ SearchTarget payload = adapterItemWithPayload.getPayload();
+ mPlugin = adapterItemWithPayload.getPlugin();
+
+ if (payload.mRemoteAction != null) {
+ RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(payload.mRemoteAction,
+ payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
+ payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
+ setTag(itemInfo);
+ }
+ showIfAvailable(mTitle, payload.mRemoteAction.getTitle().toString());
+ setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
+ adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+ }
+
+ @Override
+ public Object[] getTargetInfo() {
+ return mTargetInfo;
+ }
+
+ private void handleSelection(int eventType) {
+ ItemInfo itemInfo = (ItemInfo) getTag();
+ Launcher launcher = Launcher.getLauncher(getContext());
+
+ if (!(itemInfo instanceof RemoteActionItemInfo)) return;
+
+ RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
+ ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
+ SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SUGGEST, eventType);
+ searchTargetEvent.bundle = new Bundle();
+ searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction();
+ searchTargetEvent.bundle.putBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START,
+ remoteItemInfo.shouldStartInLauncher());
+ searchTargetEvent.bundle.putString(SearchTarget.REMOTE_ACTION_TOKEN,
+ remoteItemInfo.getToken());
+
+ if (mPlugin != null) {
+ mPlugin.notifySearchTargetEvent(searchTargetEvent);
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ handleSelection(SearchTargetEvent.SELECT);
+ }
+
+ private void showIfAvailable(TextView view, @Nullable String string) {
+ System.out.println("Plugin suggest string:" + string);
+ if (TextUtils.isEmpty(string)) {
+ view.setVisibility(GONE);
+ } else {
+ System.out.println("Plugin suggest string:" + string);
+ view.setVisibility(VISIBLE);
+ view.setText(string);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
index 1d58a06..81bcad9 100644
--- a/src/com/android/launcher3/views/ThumbnailSearchResultView.java
+++ b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
-import android.os.Bundle;
import android.util.AttributeSet;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
@@ -28,6 +28,10 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.RemoteActionItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Themes;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
@@ -37,10 +41,9 @@
* A view representing a high confidence app search result that includes shortcuts
*/
public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppCompatImageView
- implements AllAppsSearchBarController.PayloadResultHandler<Bundle> {
+ implements AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
private final Object[] mTargetInfo = createTargetInfo();
- Intent mIntent;
AllAppsSearchPlugin mPlugin;
int mPosition;
@@ -58,26 +61,51 @@
private void handleSelection(int eventType) {
Launcher launcher = Launcher.getLauncher(getContext());
- launcher.startActivitySafely(this, mIntent, null);
-
- SearchTargetEvent event = getSearchTargetEvent(
- SearchTarget.ItemType.SCREENSHOT, eventType);
+ ItemInfo itemInfo = (ItemInfo) getTag();
+ if (itemInfo instanceof RemoteActionItemInfo) {
+ RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
+ ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
+ } else {
+ ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher);
+ }
if (mPlugin != null) {
+ SearchTargetEvent event = getSearchTargetEvent(
+ SearchTarget.ItemType.SCREENSHOT, eventType);
mPlugin.notifySearchTargetEvent(event);
}
}
@Override
- public void applyAdapterInfo(AdapterItemWithPayload<Bundle> adapterItem) {
+ public void applyAdapterInfo(AdapterItemWithPayload<SearchTarget> adapterItem) {
+ Launcher launcher = Launcher.getLauncher(getContext());
mPosition = adapterItem.position;
- RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null,
- (Bitmap) adapterItem.getPayload().getParcelable("bitmap"));
+
+ SearchTarget target = adapterItem.getPayload();
+ Bitmap bitmap;
+ if (target.mRemoteAction != null) {
+ RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(target.mRemoteAction,
+ target.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
+ target.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
+ bitmap = ((BitmapDrawable) target.mRemoteAction.getIcon()
+ .loadDrawable(getContext())).getBitmap();
+ Bitmap crop = Bitmap.createBitmap(bitmap, 0,
+ bitmap.getHeight() / 2 - bitmap.getWidth() / 2,
+ bitmap.getWidth(), bitmap.getWidth());
+ bitmap = crop;
+ setTag(itemInfo);
+ } else {
+ bitmap = (Bitmap) target.bundle.getParcelable("bitmap");
+ WorkspaceItemInfo itemInfo = new WorkspaceItemInfo();
+ itemInfo.intent = new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(target.bundle.getString("uri")))
+ .setType("image/*")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ setTag(itemInfo);
+ }
+ RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null, 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);
+ setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
mPlugin = adapterItem.getPlugin();
adapterItem.setSelectionHandler(this::handleSelection);
}
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
index 9d9ccba..3f0dc39 100644
--- a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
@@ -80,7 +80,12 @@
* N number of 1x1 ratio thumbnail is rendered.
* (current N = 3)
*/
- THUMBNAIL(8);
+ THUMBNAIL(8),
+
+ /**
+ * Fallback search icon and relevant text is rendered.
+ */
+ SUGGEST(9);
private final int mId;
@@ -102,7 +107,9 @@
SHORTCUT(5, "Shortcuts", ViewType.SHORTCUT),
PEOPLE(6, "People", ViewType.PEOPLE),
SCREENSHOT(7, "Screenshots", ViewType.THUMBNAIL),
- REMOTE_ACTION(8, "Remote Actions", ViewType.SHORTCUT);
+ ACTION(8, "Actions", ViewType.SHORTCUT),
+ SUGGEST(9, "Fallback Search", ViewType.SUGGEST),
+ CHROME_TAB(10, "Chrome Tab", ViewType.SHORTCUT);
private final int mId;
diff --git a/tests/res/xml/appwidget_hidden.xml b/tests/res/xml/appwidget_hidden.xml
index 6f0e006..f6cffb5 100644
--- a/tests/res/xml/appwidget_hidden.xml
+++ b/tests/res/xml/appwidget_hidden.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="180dp"
- android:minHeight="110dp"
+ android:minWidth="1dp"
+ android:minHeight="1dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/test_layout_appwidget_blue"
android:resizeMode="horizontal|vertical"
diff --git a/tests/res/xml/appwidget_no_config.xml b/tests/res/xml/appwidget_no_config.xml
index d24dfe3..0d932dc 100644
--- a/tests/res/xml/appwidget_no_config.xml
+++ b/tests/res/xml/appwidget_no_config.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="180dp"
- android:minHeight="110dp"
+ android:minWidth="1dp"
+ android:minHeight="1dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/test_layout_appwidget_red"
android:resizeMode="horizontal|vertical"
diff --git a/tests/res/xml/appwidget_with_config.xml b/tests/res/xml/appwidget_with_config.xml
index 8403689..813e6df 100644
--- a/tests/res/xml/appwidget_with_config.xml
+++ b/tests/res/xml/appwidget_with_config.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="180dp"
- android:minHeight="110dp"
+ android:minWidth="1dp"
+ android:minHeight="1dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/test_layout_appwidget_blue"
android:configure="com.android.launcher3.testcomponent.WidgetConfigActivity"
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 5e42d9b..e118481 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -279,6 +279,8 @@
if (userManager != null) {
for (UserHandle userHandle : userManager.getUserProfiles()) {
if (!userHandle.isSystem()) {
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED,
+ "removing user " + userHandle.getIdentifier());
mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier());
}
}
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 488e763..8d594de 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -55,7 +55,9 @@
private static final int WORK_PAGE = AllAppsContainerView.AdapterHolder.WORK;
@Before
- public void createWorkProfile() throws Exception {
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
String output =
mDevice.executeShellCommand(
"pm create-user --profileOf 0 --managed TestProfile");