Merge "Adding support for listening to end callbacks when launching an intent from Launcher" into udc-dev

This commit is contained in:
TreeHugger Robot
2023-05-15 22:20:32 +00:00
committed by Android (Google) Code Review
7 changed files with 96 additions and 41 deletions
@@ -21,6 +21,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
@@ -43,6 +44,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
@@ -95,10 +97,13 @@ import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
import com.android.launcher3.util.TraceHelper;
@@ -567,6 +572,22 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
}
@Override
public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
RunnableList callbacks = new RunnableList();
ActivityOptions options = ActivityOptions.makeCustomAnimation(
this, 0, 0, Color.TRANSPARENT,
Executors.MAIN_EXECUTOR.getHandler(), null,
elapsedRealTime -> callbacks.executeAllAndDestroy());
options.setSplashScreenStyle(splashScreenStyle);
return new ActivityOptionsWrapper(options, callbacks);
}
@Override
public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
return makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED);
}
/**
* Sets a new data-source for this taskbar instance
*/
@@ -68,6 +68,7 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.SensorManager;
@@ -143,6 +144,7 @@ import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchCo
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.ObjectWrapper;
@@ -343,14 +345,16 @@ public class QuickstepLauncher extends Launcher {
}
@Override
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
// Only pause is taskbar controller is not present
mHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null);
boolean started = super.startActivitySafely(v, intent, item);
if (getTaskbarUIController() == null && !started) {
RunnableList result = super.startActivitySafely(v, intent, item);
if (getTaskbarUIController() == null && result == null) {
mHotseatPredictionController.setPauseUIUpdate(false);
} else {
result.add(() -> mHotseatPredictionController.setPauseUIUpdate(false));
}
return started;
return result;
}
@Override
@@ -370,11 +374,6 @@ public class QuickstepLauncher extends Launcher {
| ACTIVITY_STATE_USER_ACTIVE | ACTIVITY_STATE_TRANSITION_ACTIVE)) != 0) {
onStateOrResumeChanging((getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0);
}
if (((changeBits & ACTIVITY_STATE_STARTED) != 0
|| (changeBits & getActivityFlags() & ACTIVITY_STATE_DEFERRED_RESUMED) != 0)) {
mHotseatPredictionController.setPauseUIUpdate(false);
}
}
@Override
@@ -1101,6 +1100,17 @@ public class QuickstepLauncher extends Launcher {
return activityOptions;
}
@Override
public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
RunnableList callbacks = new RunnableList();
ActivityOptions options = ActivityOptions.makeCustomAnimation(
this, 0, 0, Color.TRANSPARENT,
Executors.MAIN_EXECUTOR.getHandler(), null,
elapsedRealTime -> callbacks.executeAllAndDestroy());
options.setSplashScreenStyle(splashScreenStyle);
return new ActivityOptionsWrapper(options, callbacks);
}
@Override
@BinderThread
public void enterStageSplitFromRunningApp(boolean leftOrTop) {
@@ -155,6 +155,13 @@ public abstract class BaseDraggingActivity extends BaseActivity
return wrapper;
}
@Override
public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
ActivityOptionsWrapper wrapper = super.makeDefaultActivityOptions(splashScreenStyle);
addOnResumeCallback(wrapper.onEndCallback::executeAllAndDestroy);
return wrapper;
}
@Override
protected void onStart() {
super.onStart();
+15 -7
View File
@@ -2154,30 +2154,38 @@ public class Launcher extends StatefulActivity<LauncherState>
}
@Override
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
if (!hasBeenResumed()) {
RunnableList result = new RunnableList();
// Workaround an issue where the WM launch animation is clobbered when finishing the
// recents animation into launcher. Defer launching the activity until Launcher is
// next resumed.
addOnResumeCallback(() -> startActivitySafely(v, intent, item));
addOnResumeCallback(() -> {
RunnableList actualResult = startActivitySafely(v, intent, item);
if (actualResult != null) {
actualResult.add(result::executeAllAndDestroy);
} else {
result.executeAllAndDestroy();
}
});
if (mOnDeferredActivityLaunchCallback != null) {
mOnDeferredActivityLaunchCallback.run();
mOnDeferredActivityLaunchCallback = null;
}
return true;
return result;
}
boolean success = super.startActivitySafely(v, intent, item);
if (success && v instanceof BubbleTextView) {
RunnableList result = super.startActivitySafely(v, intent, item);
if (result != null && v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
// from launcher. Since there is no callback for when the activity has finished
// launching, enable the press state and keep this reference to reset the press
// state when we return to launcher.
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
addOnResumeCallback(() -> btv.setStayPressed(false));
result.add(() -> btv.setStayPressed(false));
}
return success;
return result;
}
boolean isHotseatLayout(View layout) {
@@ -62,7 +62,8 @@ public class DefaultSearchAdapterProvider extends SearchAdapterProvider<Activity
if (mHighlightedView instanceof BubbleTextView
&& mHighlightedView.getTag() instanceof ItemInfo) {
ItemInfo itemInfo = (ItemInfo) mHighlightedView.getTag();
return mLauncher.startActivitySafely(mHighlightedView, itemInfo.getIntent(), itemInfo);
return mLauncher.startActivitySafely(
mHighlightedView, itemInfo.getIntent(), itemInfo) != null;
}
return false;
}
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.views;
import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR;
import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
@@ -45,7 +48,6 @@ import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import android.window.SplashScreen;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -289,27 +291,27 @@ public interface ActivityContext {
}
}
/**
* Sends a pending intent animating from a view.
*
* @param v View to animate.
* @param intent The pending intent being launched.
* @param item Item associated with the view.
* @return {@code true} if the intent is sent successfully.
* @return RunnableList for listening for animation finish if the activity was properly
* or started, {@code null} if the launch finished
*/
default boolean sendPendingIntentWithAnimation(
default RunnableList sendPendingIntentWithAnimation(
@NonNull View v, PendingIntent intent, @Nullable ItemInfo item) {
Bundle optsBundle = getActivityLaunchOptions(v, item).toBundle();
ActivityOptionsWrapper options = getActivityLaunchOptions(v, item);
try {
intent.send(null, 0, null, null, null, null, optsBundle);
return true;
intent.send(null, 0, null, null, null, null, options.toBundle());
return options.onEndCallback;
} catch (PendingIntent.CanceledException e) {
Toast.makeText(v.getContext(),
v.getContext().getResources().getText(R.string.shortcut_not_available),
Toast.LENGTH_SHORT).show();
}
return false;
return null;
}
/**
@@ -318,28 +320,23 @@ public interface ActivityContext {
* @param v View starting the activity.
* @param intent Base intent being launched.
* @param item Item associated with the view.
* @return {@code true} if the activity starts successfully.
* @return RunnableList for listening for animation finish if the activity was properly
* or started, {@code null} if the launch finished
*/
default boolean startActivitySafely(
default RunnableList startActivitySafely(
View v, Intent intent, @Nullable ItemInfo item) {
Preconditions.assertUIThread();
Context context = (Context) this;
if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
return null;
}
Bundle optsBundle = null;
if (v != null) {
optsBundle = getActivityLaunchOptions(v, item).toBundle();
} else if (android.os.Build.VERSION.SDK_INT >= 33
&& item != null
&& item.animationType == LauncherSettings.Animation.DEFAULT_NO_ICON) {
optsBundle = ActivityOptions.makeBasic()
.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR).toBundle();
}
ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item)
: makeDefaultActivityOptions(item != null && item.animationType == DEFAULT_NO_ICON
? SPLASH_SCREEN_STYLE_SOLID_COLOR : -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */);
UserHandle user = item == null ? null : item.user;
Bundle optsBundle = options.toBundle();
// Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
@@ -364,12 +361,12 @@ public interface ActivityContext {
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
logAppLaunch(getStatsLogManager(), item, instanceId);
}
return true;
return options.onEndCallback;
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
}
return false;
return null;
}
/** Returns {@code true} if an app launch is blocked due to safe mode. */
@@ -416,6 +413,17 @@ public interface ActivityContext {
return new ActivityOptionsWrapper(options, callback);
}
/**
* Creates a default activity option and we do not want association with any launcher element.
*/
default ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
ActivityOptions options = ActivityOptions.makeBasic();
if (Utilities.ATLEAST_T) {
options.setSplashScreenStyle(splashScreenStyle);
}
return new ActivityOptionsWrapper(options, new RunnableList());
}
/**
* Safely launches an intent for a shortcut.
*
@@ -281,7 +281,7 @@ public class OptionsPopupView extends ArrowPopup<Launcher>
if (!TextUtils.isEmpty(pickerPackage)) {
intent.setPackage(pickerPackage);
}
return launcher.startActivitySafely(v, intent, placeholderInfo(intent));
return launcher.startActivitySafely(v, intent, placeholderInfo(intent)) != null;
}
static WorkspaceItemInfo placeholderInfo(Intent intent) {