Merge "[Live tile] Finish recents animation when the phone goes to sleep in live tile mode" 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/dimens.xml b/quickstep/res/values/dimens.xml
index c85fe6c..c7c0c7e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -51,6 +51,8 @@
<dimen name="recents_empty_message_text_size">16sp</dimen>
<dimen name="recents_empty_message_text_padding">16dp</dimen>
+ <dimen name="max_shadow_radius">5dp</dimen>
+
<!-- Total space (start + end) between the task card and the edge of the screen
in various configurations -->
<dimen name="task_card_vert_space">40dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 38adf39..ae4bd96 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,14 +16,10 @@
package com.android.launcher3;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
@@ -32,11 +28,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.PendingAnimation;
+import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
/**
@@ -53,60 +46,16 @@
protected boolean isLaunchingFromRecents(@NonNull View v,
@Nullable RemoteAnimationTargetCompat[] targets) {
return mLauncher.getStateManager().getState().overviewUi
- && findTaskViewToLaunch(mLauncher, v, targets) != null;
+ && findTaskViewToLaunch(mLauncher.getOverviewPanel(), v, targets) != null;
}
@Override
protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
@NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) {
- RecentsView recentsView = mLauncher.getOverviewPanel();
- boolean skipLauncherChanges = !launcherClosing;
-
- TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
- PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
- createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
- mLauncher.getDepthController(), pa);
- anim.play(pa.buildAnim());
-
- Animator childStateAnimation = null;
- // Found a visible recents task that matches the opening app, lets launch the app from there
- Animator launcherAnim;
- final AnimatorListenerAdapter windowAnimEndListener;
- if (launcherClosing) {
- launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
- launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
- launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
-
- // Make sure recents gets fixed up by resetting task alphas and scales, etc.
- windowAnimEndListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mLauncher.getStateManager().moveToRestState();
- mLauncher.getStateManager().reapplyState();
- }
- };
- } else {
- AnimatorPlaybackController controller =
- mLauncher.getStateManager().createAnimationToNewWorkspace(NORMAL,
- RECENTS_LAUNCH_DURATION);
- controller.dispatchOnStart();
- childStateAnimation = controller.getTarget();
- launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
- windowAnimEndListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mLauncher.getStateManager().goToState(NORMAL, false);
- }
- };
- }
- anim.play(launcherAnim);
-
- // Set the current animation first, before adding windowAnimEndListener. Setting current
- // animation adds some listeners which need to be called before windowAnimEndListener
- // (the ordering of listeners matter in this case).
- mLauncher.getStateManager().setCurrentAnimation(anim, childStateAnimation);
- anim.addListener(windowAnimEndListener);
+ TaskViewUtils.composeRecentsLaunchAnimator(anim, v, appTargets, wallpaperTargets,
+ launcherClosing, mLauncher.getStateManager(), mLauncher.getOverviewPanel(),
+ mLauncher.getDepthController());
}
@Override
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index d453bc3..df1833d 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -153,6 +153,7 @@
private final float mContentTransY;
private final float mWorkspaceTransY;
private final float mClosingWindowTransY;
+ private final float mMaxShadowRadius;
private DeviceProfile mDeviceProfile;
@@ -186,6 +187,7 @@
mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
mClosingWindowTransY = res.getDimensionPixelSize(R.dimen.closing_window_trans_y);
+ mMaxShadowRadius = res.getDimensionPixelSize(R.dimen.max_shadow_radius);
mLauncher.addOnDeviceProfileChangeListener(this);
}
@@ -538,6 +540,8 @@
EXAGGERATED_EASE);
FloatProp mWindowRadius = new FloatProp(initialWindowRadius, windowRadius, 0,
RADIUS_DURATION, EXAGGERATED_EASE);
+ FloatProp mShadowRadius = new FloatProp(0, mMaxShadowRadius, 0,
+ APP_LAUNCH_DURATION, EXAGGERATED_EASE);
@Override
public void onUpdate(float percent) {
@@ -600,7 +604,8 @@
builder.withMatrix(matrix)
.withWindowCrop(crop)
.withAlpha(1f - mIconAlpha.value)
- .withCornerRadius(mWindowRadius.value);
+ .withCornerRadius(mWindowRadius.value)
+ .withShadowRadius(mShadowRadius.value);
} else {
tmpPos.set(target.position.x, target.position.y);
if (target.localBounds != null) {
@@ -750,6 +755,8 @@
FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DEACCEL_1_7);
FloatProp mScale = new FloatProp(1f, 1f, 0, duration, DEACCEL_1_7);
FloatProp mAlpha = new FloatProp(1f, 0f, 25, 125, LINEAR);
+ FloatProp mShadowRadius = new FloatProp(mMaxShadowRadius, 0, 0, duration,
+ DEACCEL_1_7);
@Override
public void onUpdate(float percent) {
@@ -771,7 +778,8 @@
matrix.postTranslate(tmpPos.x, tmpPos.y);
builder.withMatrix(matrix)
.withAlpha(mAlpha.value)
- .withCornerRadius(windowCornerRadius);
+ .withCornerRadius(windowCornerRadius)
+ .withShadowRadius(mShadowRadius.value);
} else {
matrix.setTranslate(tmpPos.x, tmpPos.y);
builder.withMatrix(matrix)
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 5b066c6..b5ba8a6 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -108,6 +108,8 @@
AllAppsSectionDecorator.SectionDecorationHandler mDecorationHandler;
+ @Nullable private List<ItemInfo> mPendingPredictedItems;
+
public PredictionRowView(@NonNull Context context) {
this(context, null);
}
@@ -146,6 +148,10 @@
private void updateVisibility() {
setVisibility(mPredictionsEnabled ? VISIBLE : GONE);
+ if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && mLauncher.getAppsView() != null
+ && mLauncher.getAppsView().getActiveRecyclerView() != null) {
+ mLauncher.getAppsView().invalidate();
+ }
}
@Override
@@ -203,6 +209,16 @@
* we can optimize by swapping them in place.
*/
public void setPredictedApps(List<ItemInfo> items) {
+ if (isShown() && getWindowVisibility() == View.VISIBLE) {
+ mPendingPredictedItems = items;
+ return;
+ }
+
+ applyPredictedApps(items);
+ }
+
+ private void applyPredictedApps(List<ItemInfo> items) {
+ mPendingPredictedItems = null;
mPredictedApps.clear();
items.stream()
.filter(itemInfo -> itemInfo instanceof WorkspaceItemInfo)
@@ -341,4 +357,13 @@
public View getFocusedChild() {
return getChildAt(0);
}
+
+ @Override
+ public void onVisibilityAggregated(boolean isVisible) {
+ super.onVisibilityAggregated(isVisible);
+
+ if (mPendingPredictedItems != null && !isVisible) {
+ applyPredictedApps(mPendingPredictedItems);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 3807350..76bab59 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -251,6 +251,26 @@
* Sets or updates the predicted items
*/
public void setPredictedItems(FixedContainerItems items) {
+ if (mHotseat.isShown() && mHotseat.getWindowVisibility() == View.VISIBLE) {
+ mHotseat.setOnVisibilityAggregatedCallback((isVisible) -> {
+ if (isVisible) {
+ return;
+ }
+ mHotseat.setOnVisibilityAggregatedCallback(null);
+
+ applyPredictedItems(items);
+ });
+ } else {
+ mHotseat.setOnVisibilityAggregatedCallback(null);
+
+ applyPredictedItems(items);
+ }
+ }
+
+ /**
+ * Sets or updates the predicted items only once the hotseat becomes hidden to the user
+ */
+ private void applyPredictedItems(FixedContainerItems items) {
mPredictedItems = items.items;
if (mPredictedItems.isEmpty()) {
HotseatRestoreHelper.restoreBackup(mLauncher);
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 5e05a7d..dbf75fa 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -41,10 +41,14 @@
import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager;
@@ -104,6 +108,7 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.function.Consumer;
/**
@@ -715,6 +720,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);
@@ -790,7 +797,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
@@ -807,7 +815,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. */
@@ -1370,17 +1381,64 @@
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
mActivityInterface.onSwipeUpToRecentsComplete();
- if (mRecentsAnimationController != null) {
- mRecentsAnimationController.setDeferCancelUntilNextTransition(true /* defer */,
- true /* screenshot */);
- }
mRecentsView.onSwipeUpAnimationSuccess();
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler(
+ this::launchOtherTaskInLiveTileMode);
+ }
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
doLogGesture(RECENTS, mRecentsView.getCurrentPageTaskView());
reset();
}
+ private void launchOtherTaskInLiveTileMode(RemoteAnimationTargetCompat appearedTaskTarget) {
+ TaskView taskView = mRecentsView.getTaskView(appearedTaskTarget.taskId);
+ if (taskView == null) {
+ return;
+ }
+
+ RemoteAnimationTargetCompat[] apps = Arrays.copyOf(
+ mRecentsAnimationTargets.apps,
+ mRecentsAnimationTargets.apps.length + 1);
+ apps[apps.length - 1] = appearedTaskTarget;
+ boolean launcherClosing =
+ taskIsATargetWithMode(apps, mActivity.getTaskId(), MODE_CLOSING);
+
+ AnimatorSet anim = new AnimatorSet();
+ TaskViewUtils.composeRecentsLaunchAnimator(
+ anim, taskView, apps,
+ mRecentsAnimationTargets.wallpapers, launcherClosing,
+ mActivity.getStateManager(), mRecentsView,
+ mActivityInterface.getDepthController());
+ anim.addListener(new AnimatorListenerAdapter(){
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ cleanUp(false);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ cleanUp(true);
+ }
+
+ private void cleanUp(boolean canceled) {
+ if (mRecentsAnimationController != null) {
+ mRecentsAnimationController.finish(false /* toRecents */,
+ null /* onFinishComplete */);
+ if (canceled) {
+ mRecentsAnimationController = null;
+ } else {
+ mActivityInterface.onLaunchTaskSuccess();
+ }
+ ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
+ }
+ }
+ });
+ anim.start();
+ }
+
private void addLiveTileOverlay() {
if (LiveTileOverlay.INSTANCE.attach(mActivity.getRootView().getOverlay())) {
mRecentsView.setLiveTileOverlayAttached(true);
@@ -1438,39 +1496,33 @@
protected void startNewTask(Consumer<Boolean> resultCallback) {
// Launch the task user scrolled to (mRecentsView.getNextPage()).
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- // We finish recents animation inside launchTask() when live tile is enabled.
- mRecentsView.getNextPageTaskView().launchTask(false /* animate */,
- true /* freezeTaskList */);
- } else {
- if (!mCanceled) {
- TaskView nextTask = mRecentsView.getNextPageTaskView();
- if (nextTask != null) {
- int taskId = nextTask.getTask().key.id;
- mGestureState.updateLastStartedTaskId(taskId);
- boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
- .contains(taskId);
- nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
- success -> {
- resultCallback.accept(success);
- if (success) {
- if (hasTaskPreviouslyAppeared) {
- onRestartPreviouslyAppearedTask();
- }
- } else {
- mActivityInterface.onLaunchTaskFailed();
- nextTask.notifyTaskLaunchFailed(TAG);
- mRecentsAnimationController.finish(true /* toRecents */, null);
+ if (!mCanceled) {
+ TaskView nextTask = mRecentsView.getNextPageTaskView();
+ if (nextTask != null) {
+ int taskId = nextTask.getTask().key.id;
+ mGestureState.updateLastStartedTaskId(taskId);
+ boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
+ .contains(taskId);
+ nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
+ success -> {
+ resultCallback.accept(success);
+ if (success) {
+ if (hasTaskPreviouslyAppeared) {
+ onRestartPreviouslyAppearedTask();
}
- }, MAIN_EXECUTOR.getHandler());
- } else {
- mActivityInterface.onLaunchTaskFailed();
- Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show();
- mRecentsAnimationController.finish(true /* toRecents */, null);
- }
+ } else {
+ mActivityInterface.onLaunchTaskFailed();
+ nextTask.notifyTaskLaunchFailed(TAG);
+ mRecentsAnimationController.finish(true /* toRecents */, null);
+ }
+ }, MAIN_EXECUTOR.getHandler());
+ } else {
+ mActivityInterface.onLaunchTaskFailed();
+ Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show();
+ mRecentsAnimationController.finish(true /* toRecents */, null);
}
- mCanceled = false;
}
+ mCanceled = false;
}
/**
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 51f5e5d..62bbf4d 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;
@@ -89,24 +90,6 @@
}
/**
- * Notifies the controller that we want to defer cancel until the next app transition starts.
- * If {@param screenshot} is set, then we will receive a screenshot on the next
- * {@link RecentsAnimationCallbacks#onAnimationCanceled(ThumbnailData)} and we must also call
- * {@link #cleanupScreenshot()} when that screenshot is no longer used.
- */
- public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
- mController.setDeferCancelUntilNextTransition(defer, screenshot);
- }
-
- /**
- * Cleans up the screenshot previously returned from
- * {@link RecentsAnimationCallbacks#onAnimationCanceled(ThumbnailData)}.
- */
- public void cleanupScreenshot() {
- UI_HELPER_EXECUTOR.execute(() -> mController.cleanupScreenshot());
- }
-
- /**
* Remove task remote animation target from
* {@link RecentsAnimationCallbacks#onTaskAppeared(RemoteAnimationTargetCompat)}}.
*/
@@ -149,6 +132,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/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index b6eaa1c..a46de1f 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -29,6 +29,7 @@
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -66,6 +67,8 @@
// How much further we can drag past recents, as a factor of mTransitionDragLength.
protected float mDragLengthFactor = 1;
+ protected final float mMaxShadowRadius;
+
protected AnimatorControllerWithResistance mWindowTransitionController;
public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState,
@@ -80,6 +83,9 @@
mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
mDeviceState.getRotationTouchHelper().getDisplayRotation());
mTaskViewSimulator.setDrawsBelowRecents(true);
+
+ mMaxShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.max_shadow_radius);
+ mTransformParams.setShadowRadius(mMaxShadowRadius);
}
protected void initTransitionEndpoints(DeviceProfile dp) {
@@ -251,9 +257,11 @@
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
+ float shadowRadius = Utilities.mapRange(progress, mMaxShadowRadius, 0);
mTransformParams
.setTargetAlpha(getWindowAlpha(progress))
- .setCornerRadius(cornerRadius);
+ .setCornerRadius(cornerRadius)
+ .setShadowRadius(mMaxShadowRadius);
mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
@@ -264,7 +272,8 @@
Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
builder.withMatrix(mMatrix)
.withWindowCrop(mCropRect)
- .withCornerRadius(params.getCornerRadius());
+ .withCornerRadius(params.getCornerRadius())
+ .withShadowRadius(params.getShadowRadius());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index cad51f4..f38c1ea 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
@@ -31,6 +32,8 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import java.util.function.Consumer;
+
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
private RecentsAnimationController mController;
@@ -39,6 +42,7 @@
// Temporary until we can hook into gesture state events
private GestureState mLastGestureState;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
+ private Consumer<RemoteAnimationTargetCompat> mLaunchOtherTaskHandler;
/**
* Preloads the recents animation.
@@ -88,22 +92,21 @@
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- if (thumbnailData != null) {
- // If a screenshot is provided, switch to the screenshot before cleaning up
- activityInterface.switchRunningTaskViewToScreenshot(thumbnailData,
- () -> cleanUpRecentsAnimation(thumbnailData));
- } else {
- cleanUpRecentsAnimation(null /* canceledThumbnail */);
- }
+ cleanUpRecentsAnimation();
}
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
- cleanUpRecentsAnimation(null /* canceledThumbnail */);
+ cleanUpRecentsAnimation();
}
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ if (mLaunchOtherTaskHandler != null
+ && mLastGestureState.getEndTarget() == RECENTS) {
+ mLaunchOtherTaskHandler.accept(appearedTaskTarget);
+ return;
+ }
if (mController != null) {
if (mLastAppearedTaskTarget == null
|| appearedTaskTarget.taskId != mLastAppearedTaskTarget.taskId) {
@@ -138,6 +141,15 @@
}
/**
+ * The passed-in handler is used to render side task launch animation in recents in live tile
+ * mode.
+ */
+ public void setLaunchOtherTaskInLiveTileModeHandler(
+ Consumer<RemoteAnimationTargetCompat> handler) {
+ mLaunchOtherTaskHandler = handler;
+ }
+
+ /**
* Finishes the running recents animation.
*/
public void finishRunningRecentsAnimation(boolean toHome) {
@@ -146,7 +158,7 @@
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome
? mController::finishAnimationToHome
: mController::finishAnimationToApp);
- cleanUpRecentsAnimation(null /* canceledThumbnail */);
+ cleanUpRecentsAnimation();
}
}
@@ -173,12 +185,7 @@
/**
* Cleans up the recents animation entirely.
*/
- private void cleanUpRecentsAnimation(ThumbnailData canceledThumbnail) {
- // Clean up the screenshot if necessary
- if (mController != null && canceledThumbnail != null) {
- mController.cleanupScreenshot();
- }
-
+ private void cleanUpRecentsAnimation() {
// Release all the target leashes
if (mTargets != null) {
mTargets.release();
@@ -194,6 +201,7 @@
mTargets = null;
mLastGestureState = null;
mLastAppearedTaskTarget = null;
+ mLaunchOtherTaskHandler = null;
}
public void dump() {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index a5af181..7299c38 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -17,15 +17,20 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
@@ -35,12 +40,16 @@
import android.os.Build;
import android.view.View;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.BaseActivity;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskViewSimulator;
@@ -67,8 +76,7 @@
* opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
*/
public static TaskView findTaskViewToLaunch(
- BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
- RecentsView recentsView = activity.getOverviewPanel();
+ RecentsView recentsView, View v, RemoteAnimationTargetCompat[] targets) {
if (v instanceof TaskView) {
TaskView taskView = (TaskView) v;
return recentsView.isTaskViewVisible(taskView) ? taskView : null;
@@ -130,7 +138,8 @@
SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
final RemoteAnimationTargets targets =
- new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
+ new RemoteAnimationTargets(appTargets, wallpaperTargets,
+ ENABLE_QUICKSTEP_LIVE_TILE.get() ? MODE_CLOSING : MODE_OPENING);
targets.addReleaseCheck(applier);
TransformParams params = new TransformParams()
@@ -235,4 +244,57 @@
TOUCH_RESPONSE_INTERPOLATOR);
}
}
+
+ public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
+ @NonNull RemoteAnimationTargetCompat[] appTargets,
+ @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing,
+ @NonNull StateManager stateManager, @NonNull RecentsView recentsView,
+ @NonNull DepthController depthController) {
+ boolean skipLauncherChanges = !launcherClosing;
+
+ TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);
+ PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
+ createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
+ depthController, pa);
+ anim.play(pa.buildAnim());
+
+ Animator childStateAnimation = null;
+ // Found a visible recents task that matches the opening app, lets launch the app from there
+ Animator launcherAnim;
+ final AnimatorListenerAdapter windowAnimEndListener;
+ if (launcherClosing) {
+ launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
+ launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
+ launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
+
+ // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+ windowAnimEndListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ stateManager.moveToRestState();
+ stateManager.reapplyState();
+ }
+ };
+ } else {
+ AnimatorPlaybackController controller =
+ stateManager.createAnimationToNewWorkspace(NORMAL,
+ RECENTS_LAUNCH_DURATION);
+ controller.dispatchOnStart();
+ childStateAnimation = controller.getTarget();
+ launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
+ windowAnimEndListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ stateManager.goToState(NORMAL, false);
+ }
+ };
+ }
+ anim.play(launcherAnim);
+
+ // Set the current animation first, before adding windowAnimEndListener. Setting current
+ // animation adds some listeners which need to be called before windowAnimEndListener
+ // (the ordering of listeners matter in this case).
+ stateManager.setCurrentAnimation(anim, childStateAnimation);
+ anim.addListener(windowAnimEndListener);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7bf8fba..d3c4f55 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -732,8 +732,11 @@
private void reset() {
mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
mGestureState = DEFAULT_STATE;
- // By default, use batching of the input events
- mInputEventReceiver.setBatchingEnabled(true);
+ // 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/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index de44e07..bb84380 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 {}
@@ -541,6 +539,7 @@
* @return "MyObject@1234"
*/
private static String extractObjectNameAndAddress(String stringToExtract) {
- return stringToExtract.substring(stringToExtract.lastIndexOf(DELIMITER_DOT));
+ int index = stringToExtract.lastIndexOf(DELIMITER_DOT);
+ return index >= 0 ? stringToExtract.substring(index) : "";
}
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 3a54bd6..08fe48d 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -322,7 +322,8 @@
Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
builder.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
- .withCornerRadius(getCurrentCornerRadius());
+ .withCornerRadius(getCurrentCornerRadius())
+ .withShadowRadius(params.getShadowRadius());
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
// When relativeLayer = 0, it reverts the surfaces back to the original order.
diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
index 45f49bb..c6a0c66 100644
--- a/quickstep/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/src/com/android/quickstep/util/TransformParams.java
@@ -57,6 +57,7 @@
private float mProgress;
private float mTargetAlpha;
private float mCornerRadius;
+ private float mShadowRadius;
private RemoteAnimationTargets mTargetSet;
private SurfaceTransactionApplier mSyncTransactionApplier;
private SurfaceControl mRecentsSurface;
@@ -68,6 +69,7 @@
mProgress = 0;
mTargetAlpha = 1;
mCornerRadius = -1;
+ mShadowRadius = 0;
}
/**
@@ -91,6 +93,14 @@
}
/**
+ * Sets the shadow radius of the transformed window, in pixels.
+ */
+ public TransformParams setShadowRadius(float shadowRadius) {
+ mShadowRadius = shadowRadius;
+ return this;
+ }
+
+ /**
* Specifies the alpha of the transformed window. Default is 1.
*/
public TransformParams setTargetAlpha(float targetAlpha) {
@@ -197,6 +207,10 @@
return mCornerRadius;
}
+ public float getShadowRadius() {
+ return mShadowRadius;
+ }
+
public SurfaceControl getRecentsSurface() {
return mRecentsSurface;
}
diff --git a/res/drawable/ic_allapps_search.xml b/res/drawable/ic_allapps_search.xml
index 2aeb947..c0e20f1 100644
--- a/res/drawable/ic_allapps_search.xml
+++ b/res/drawable/ic_allapps_search.xml
@@ -19,6 +19,6 @@
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
- android:fillColor="?android:attr/colorAccent"
+ android:fillColor="?android:attr/textColorTertiary"
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
</vector>
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 67ec664..0041c9a 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,8 +15,7 @@
<!-- The top and bottom paddings are defined in this container, but since we want
the list view to span the full width (for touch interception purposes), we
will bake the left/right padding into that view's background itself. -->
-<com.android.launcher3.allapps.LauncherAllAppsContainerView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.allapps.LauncherAllAppsContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/apps_view"
android:theme="?attr/allAppsTheme"
android:layout_width="match_parent"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6ab8150..6c58c0e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -59,7 +59,7 @@
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
<string name="all_apps_search_bar_hint">Search apps</string>
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
- <string name="all_apps_on_device_search_bar_hint">Search this phone and more...</string>
+ <string name="all_apps_on_device_search_bar_hint">Search this phone and more…</string>
<!-- Loading apps text. [CHAR_LIMIT=50] -->
<string name="all_apps_loading_message">Loading apps…</string>
<!-- No-search-results text. [CHAR_LIMIT=50] -->
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 6547b53..e4bdb39 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -25,6 +25,10 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
+
+import java.util.function.Consumer;
+
/**
* View class that represents the bottom row of the home screen.
*/
@@ -34,6 +38,7 @@
private boolean mHasVerticalHotseat;
private Workspace mWorkspace;
private boolean mSendTouchToWorkspace;
+ @Nullable private Consumer<Boolean> mOnVisibilityAggregatedCallback;
public Hotseat(Context context) {
this(context, null);
@@ -129,4 +134,18 @@
}
return event.getY() > getCellHeight();
}
+
+ @Override
+ public void onVisibilityAggregated(boolean isVisible) {
+ super.onVisibilityAggregated(isVisible);
+
+ if (mOnVisibilityAggregatedCallback != null) {
+ mOnVisibilityAggregatedCallback.accept(isVisible);
+ }
+ }
+
+ /** Sets a callback to be called onVisibilityAggregated */
+ public void setOnVisibilityAggregatedCallback(@Nullable Consumer<Boolean> callback) {
+ mOnVisibilityAggregatedCallback = callback;
+ }
}
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/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index 0214c35..f2a1f85 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -101,8 +101,8 @@
* Handles grouping and drawing of items in the same all apps sections.
*/
public static class SectionDecorationHandler {
- private static final int FILL_ALPHA = (int) (.3f * 255);
- private static final int FOCUS_ALPHA = (int) (.8f * 255);
+ private static final int FILL_ALPHA = 0;
+ private static final int FOCUS_ALPHA = (int) (.9f * 255);
protected RectF mBounds = new RectF();
private final boolean mIsFullWidth;
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/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 2b4520b..c0d5882 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -49,6 +49,7 @@
import android.util.TimingLogger;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
@@ -306,6 +307,7 @@
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
final boolean isSafeMode = pmHelper.isSafeMode();
final boolean isSdCardReady = Utilities.isBootCompleted();
+ final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context);
boolean clearDb = false;
try {
@@ -391,6 +393,7 @@
WorkspaceItemInfo info;
LauncherAppWidgetInfo appWidgetInfo;
+ LauncherAppWidgetProviderInfo widgetProviderInfo;
Intent intent;
String targetPkg;
@@ -720,6 +723,19 @@
+ appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
continue;
}
+ widgetProviderInfo =
+ widgetHelper.getLauncherAppWidgetInfo(appWidgetId);
+ if (widgetProviderInfo != null
+ && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
+ || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
+ // This can happen when display size changes.
+ c.markDeleted("Widget removed, min sizes not met: "
+ + "span=" + appWidgetInfo.spanX + "x"
+ + appWidgetInfo.spanY + " minSpan="
+ + widgetProviderInfo.minSpanX + "x"
+ + widgetProviderInfo.minSpanY);
+ continue;
+ }
if (!c.isOnWorkspaceOrHotseat()) {
c.markDeleted("Widget found where container != " +
"CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
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/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/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 77cec80..15ff2f5 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -42,7 +42,7 @@
*/
public class ScrimView<T extends Launcher> extends View implements Insettable, OnChangeListener {
- private static final float SCRIM_ALPHA = .75f;
+ private static final float SCRIM_ALPHA = .8f;
protected final T mLauncher;
private final WallpaperColorInfo mWallpaperColorInfo;
protected final int mEndScrim;
diff --git a/src/com/android/launcher3/views/SearchResultIconRow.java b/src/com/android/launcher3/views/SearchResultIconRow.java
index 313ae5e..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;
@@ -83,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));
}
@@ -102,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);
@@ -110,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);
}
});
diff --git a/src/com/android/launcher3/views/SearchResultPeopleView.java b/src/com/android/launcher3/views/SearchResultPeopleView.java
index 0c9a22f..f20b080 100644
--- a/src/com/android/launcher3/views/SearchResultPeopleView.java
+++ b/src/com/android/launcher3/views/SearchResultPeopleView.java
@@ -23,9 +23,12 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
+import android.os.Process;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
@@ -41,7 +44,8 @@
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsGridAdapter;
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
-import com.android.launcher3.util.Themes;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
@@ -105,15 +109,14 @@
mPlugin = adapterItemWithPayload.getPlugin();
mTitleView.setText(payload.getString("title"));
mIntent = payload.getParcelable("intent");
- Bitmap icon = payload.getParcelable("icon");
- if (icon != null) {
- RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
- float radius = Themes.getDialogCornerRadius(getContext());
- d.setCornerRadius(radius);
- d.setBounds(0, 0, mIconSize, mIconSize);
- BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(),
- Bitmap.createScaledBitmap(icon, mIconSize, mIconSize, false));
- mIconView.setBackground(d);
+ Bitmap contactIcon = payload.getParcelable("icon");
+ try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
+ BitmapInfo badgeInfo = li.createBadgedIconBitmap(
+ getAppIcon(mIntent.getPackage()), Process.myUserHandle(),
+ Build.VERSION.SDK_INT);
+ setIcon(li.badgeBitmap(roundBitmap(contactIcon), badgeInfo).icon, false);
+ } catch (Exception e) {
+ setIcon(contactIcon, true);
}
ArrayList<Bundle> providers = payload.getParcelableArrayList("providers");
@@ -123,17 +126,14 @@
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);
+ String pkg = provider.getString("package_name");
+ Drawable appIcon = getAppIcon(pkg);
+ if (appIcon != null) {
MAIN_EXECUTOR.post(() -> button.setImageDrawable(appIcon));
- } catch (PackageManager.NameNotFoundException ignored) {
}
-
});
+ button.setVisibility(VISIBLE);
} else {
button.setVisibility(GONE);
}
@@ -141,6 +141,45 @@
adapterItemWithPayload.setSelectionHandler(this::handleSelection);
}
+ /**
+ * Normalizes the bitmap to look like rounded App Icon
+ * TODO(b/170234747) to support styling, generate adaptive icon drawable and generate
+ * bitmap from it.
+ */
+ private Bitmap roundBitmap(Bitmap icon) {
+ final RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
+ d.setCornerRadius(R.attr.folderIconRadius);
+ d.setBounds(0, 0, mIconSize, mIconSize);
+ final Bitmap bitmap = Bitmap.createBitmap(d.getBounds().width(), d.getBounds().height(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ d.draw(canvas);
+ return bitmap;
+ }
+
+ private void setIcon(Bitmap icon, Boolean round) {
+ if (round) {
+ RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
+ d.setCornerRadius(R.attr.folderIconRadius);
+ d.setBounds(0, 0, mIconSize, mIconSize);
+ mIconView.setBackground(d);
+ } else {
+ mIconView.setBackground(new BitmapDrawable(getResources(), icon));
+ }
+ }
+
+
+ private Drawable getAppIcon(String pkg) {
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
+ pkg, 0);
+ return applicationInfo.loadIcon(mPackageManager);
+ } catch (PackageManager.NameNotFoundException ignored) {
+ return null;
+ }
+ }
+
@Override
public Object[] getTargetInfo() {
return mTargetInfo;
@@ -155,7 +194,8 @@
SearchTarget.ItemType.PEOPLE,
SearchTargetEvent.CHILD_SELECT);
searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.bundle.putParcelable("intent", mIntent);
+ searchTargetEvent.bundle.putParcelable("intent", intent);
+ searchTargetEvent.bundle.putString("title", mTitleView.getText().toString());
searchTargetEvent.bundle.putBundle("provider", provider);
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
@@ -172,6 +212,7 @@
eventType);
searchTargetEvent.bundle = new Bundle();
searchTargetEvent.bundle.putParcelable("intent", mIntent);
+ searchTargetEvent.bundle.putString("title", mTitleView.getText().toString());
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
}
diff --git a/src/com/android/launcher3/views/SearchResultSuggestRow.java b/src/com/android/launcher3/views/SearchResultSuggestRow.java
index b5abbcc..6543c76 100644
--- a/src/com/android/launcher3/views/SearchResultSuggestRow.java
+++ b/src/com/android/launcher3/views/SearchResultSuggestRow.java
@@ -96,7 +96,8 @@
private void handleSelection(int eventType) {
ItemInfo itemInfo = (ItemInfo) getTag();
Launcher launcher = Launcher.getLauncher(getContext());
- if (itemInfo instanceof RemoteActionItemInfo) return;
+
+ if (!(itemInfo instanceof RemoteActionItemInfo)) return;
RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
index bbc4773..81bcad9 100644
--- a/src/com/android/launcher3/views/ThumbnailSearchResultView.java
+++ b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
@@ -86,9 +86,12 @@
RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(target.mRemoteAction,
target.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
target.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
- ItemClickHandler.onClickRemoteAction(launcher, itemInfo);
bitmap = ((BitmapDrawable) target.mRemoteAction.getIcon()
- .loadDrawable(getContext())).getBitmap();
+ .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");
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/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index c9c846f..153b3ce 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -88,10 +88,6 @@
? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
: LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
- // b/156044202
- mLauncher.log("Hierarchy before swiping up to overview:");
- mLauncher.dumpViewHierarchy();
-
mLauncher.sendPointer(
downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
mLauncher.executeAndWaitForLauncherEvent(