Merge "Adding support for listening to end callbacks when launching an intent from Launcher" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
15bc0d388a
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user