Snap for 12210778 from f3a85e17af to 24Q4-release
Change-Id: Ia2cf4a909f7c73669e44a1b951d9d2f3313287a3
This commit is contained in:
+44
-19
@@ -25,6 +25,7 @@ import android.os.Debug;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.Launcher;
|
||||
@@ -38,6 +39,7 @@ import com.android.wm.shell.desktopmode.IDesktopTaskListener;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Controls the visibility of the workspace and the resumed / paused state when desktop mode
|
||||
@@ -56,7 +58,7 @@ public class DesktopVisibilityController {
|
||||
private boolean mGestureInProgress;
|
||||
|
||||
@Nullable
|
||||
private IDesktopTaskListener mDesktopTaskListener;
|
||||
private DesktopTaskListenerImpl mDesktopTaskListener;
|
||||
|
||||
public DesktopVisibilityController(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
@@ -66,24 +68,7 @@ public class DesktopVisibilityController {
|
||||
* Register a listener with System UI to receive updates about desktop tasks state
|
||||
*/
|
||||
public void registerSystemUiListener() {
|
||||
mDesktopTaskListener = new IDesktopTaskListener.Stub() {
|
||||
@Override
|
||||
public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
if (displayId == mLauncher.getDisplayId()) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
|
||||
}
|
||||
setVisibleDesktopTasksCount(visibleTasksCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStashedChanged(int displayId, boolean stashed) {
|
||||
Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
|
||||
}
|
||||
};
|
||||
mDesktopTaskListener = new DesktopTaskListenerImpl(this, mLauncher.getDisplayId());
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(mDesktopTaskListener);
|
||||
}
|
||||
|
||||
@@ -92,6 +77,7 @@ public class DesktopVisibilityController {
|
||||
*/
|
||||
public void unregisterSystemUiListener() {
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(null);
|
||||
mDesktopTaskListener.release();
|
||||
mDesktopTaskListener = null;
|
||||
}
|
||||
|
||||
@@ -355,4 +341,43 @@ public class DesktopVisibilityController {
|
||||
*/
|
||||
void onDesktopVisibilityChanged(boolean visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for the IDesktopTaskListener stub to prevent lingering references to the launcher
|
||||
* activity via the controller.
|
||||
*/
|
||||
private static class DesktopTaskListenerImpl extends IDesktopTaskListener.Stub {
|
||||
|
||||
private DesktopVisibilityController mController;
|
||||
private final int mDisplayId;
|
||||
|
||||
DesktopTaskListenerImpl(@NonNull DesktopVisibilityController controller, int displayId) {
|
||||
mController = controller;
|
||||
mDisplayId = displayId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any references to the controller.
|
||||
*/
|
||||
void release() {
|
||||
mController = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
if (mController != null && displayId == mDisplayId) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
|
||||
}
|
||||
mController.setVisibleDesktopTasksCount(visibleTasksCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStashedChanged(int displayId, boolean stashed) {
|
||||
Log.w(TAG, "IDesktopTaskListener: onStashedChanged is deprecated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,24 @@
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
|
||||
import com.android.launcher3.popup.SystemShortcut;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
// TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar.
|
||||
/** Base for common behavior between taskbar window contexts. */
|
||||
public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext {
|
||||
public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext,
|
||||
SystemShortcut.BubbleActivityStarter {
|
||||
|
||||
protected final LayoutInflater mLayoutInflater;
|
||||
private final List<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
|
||||
@@ -48,6 +53,18 @@ public abstract class BaseTaskbarContext extends ContextThemeWrapper implements
|
||||
return mDPChangeListeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showShortcutBubble(ShortcutInfo info) {
|
||||
if (info == null) return;
|
||||
SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showAppBubble(Intent intent) {
|
||||
if (intent == null || intent.getPackage() == null) return;
|
||||
SystemUiProxy.INSTANCE.get(this).showAppBubble(intent);
|
||||
}
|
||||
|
||||
/** Callback invoked when a drag is initiated within this context. */
|
||||
public abstract void onDragStart();
|
||||
|
||||
|
||||
@@ -225,9 +225,12 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
// Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so
|
||||
// avoid updating taskbar state in that situation (when it's non-interactive -- or
|
||||
// "background") to avoid premature animations.
|
||||
if (ENABLE_SHELL_TRANSITIONS && isVisible
|
||||
&& mLauncher.getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE)
|
||||
&& !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) {
|
||||
LauncherState state = mLauncher.getStateManager().getState();
|
||||
boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE)
|
||||
&& !state.isTaskbarAlignedWithHotseat(mLauncher);
|
||||
if ((ENABLE_SHELL_TRANSITIONS
|
||||
&& isVisible
|
||||
&& (nonInteractiveState || mSkipLauncherVisibilityChange))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
|
||||
* stashed handle to wrap around the hotseat items.
|
||||
*/
|
||||
public Animator createRevealAnimToIsStashed(boolean isStashed, Rect taskbarToHotseatOffsets) {
|
||||
Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds());
|
||||
Rect visualBounds = mControllers.taskbarViewController.getIconLayoutVisualBounds();
|
||||
float startRadius = mStashedHandleRadius;
|
||||
|
||||
if (DisplayController.isTransientTaskbar(mActivity)) {
|
||||
|
||||
@@ -927,7 +927,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
|
||||
fromInit);
|
||||
boolean isShadeVisible = (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
|
||||
onNotificationShadeExpandChanged(isShadeVisible, fromInit);
|
||||
onNotificationShadeExpandChanged(isShadeVisible, fromInit || isPhoneMode());
|
||||
mControllers.taskbarViewController.setRecentsButtonDisabled(
|
||||
mControllers.navbarButtonsViewController.isRecentsDisabled()
|
||||
|| isNavBarKidsModeActive());
|
||||
|
||||
+3
@@ -85,6 +85,9 @@ public class TaskbarForceVisibleImmersiveController implements TouchController {
|
||||
|
||||
/** Update values tracked via sysui flags. */
|
||||
public void updateSysuiFlags(@SystemUiStateFlags long sysuiFlags) {
|
||||
if (mContext.isPhoneMode()) {
|
||||
return;
|
||||
}
|
||||
mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) == 0;
|
||||
if (mContext.isNavBarForceVisible()) {
|
||||
if (mIsImmersiveMode) {
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.util.LogUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -69,6 +70,9 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba
|
||||
private static final SystemShortcut.Factory<BaseTaskbarContext>
|
||||
APP_INFO = SystemShortcut.AppInfo::new;
|
||||
|
||||
private static final SystemShortcut.Factory<BaseTaskbarContext>
|
||||
BUBBLE = SystemShortcut.BubbleShortcut::new;
|
||||
|
||||
private final TaskbarActivityContext mContext;
|
||||
private final PopupDataProvider mPopupDataProvider;
|
||||
|
||||
@@ -182,10 +186,13 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba
|
||||
// Create a Stream of all applicable system shortcuts
|
||||
private Stream<SystemShortcut.Factory> getSystemShortcuts() {
|
||||
// append split options to APP_INFO shortcut, the order here will reflect in the popup
|
||||
return Stream.concat(
|
||||
Stream.of(APP_INFO),
|
||||
mControllers.uiController.getSplitMenuOptions()
|
||||
);
|
||||
ArrayList<SystemShortcut.Factory> shortcuts = new ArrayList<>();
|
||||
shortcuts.add(APP_INFO);
|
||||
shortcuts.addAll(mControllers.uiController.getSplitMenuOptions().toList());
|
||||
if (com.android.wm.shell.Flags.enableBubbleAnything()) {
|
||||
shortcuts.add(BUBBLE);
|
||||
}
|
||||
return shortcuts.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.view.animation.Interpolator;
|
||||
import android.view.animation.PathInterpolator;
|
||||
|
||||
import com.android.launcher3.anim.AnimatedFloat;
|
||||
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
|
||||
@@ -86,6 +87,10 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa
|
||||
* Updates the scrim state based on the flags.
|
||||
*/
|
||||
public void updateStateForSysuiFlags(@SystemUiStateFlags long stateFlags, boolean skipAnim) {
|
||||
if (mActivity.isPhoneMode()) {
|
||||
// There is no scrim for the bar in the phone mode.
|
||||
return;
|
||||
}
|
||||
if (isBubbleBarEnabled() && DisplayController.isTransientTaskbar(mActivity)) {
|
||||
// These scrims aren't used if bubble bar & transient taskbar are active.
|
||||
return;
|
||||
@@ -97,10 +102,20 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa
|
||||
private boolean shouldShowScrim() {
|
||||
final boolean bubblesExpanded = (mSysUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0;
|
||||
boolean isShadeVisible = (mSysUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
|
||||
BubbleControllers bubbleControllers = mActivity.getBubbleControllers();
|
||||
boolean isBubbleControllersPresented = bubbleControllers != null;
|
||||
// when the taskbar is in persistent mode, we hide the task bar icons on bubble bar expand,
|
||||
// which makes the taskbar invisible, so need to check if the bubble bar is not on home
|
||||
// to show the scrim view
|
||||
boolean showScrimForBubbles = bubblesExpanded
|
||||
&& !mTaskbarVisible
|
||||
&& isBubbleControllersPresented
|
||||
&& !DisplayController.isTransientTaskbar(mActivity)
|
||||
&& !bubbleControllers.bubbleStashController.isBubblesShowingOnHome();
|
||||
return bubblesExpanded && !mControllers.navbarButtonsViewController.isImeVisible()
|
||||
&& !isShadeVisible
|
||||
&& !mControllers.taskbarStashController.isStashed()
|
||||
&& mTaskbarVisible;
|
||||
&& (mTaskbarVisible || showScrimForBubbles);
|
||||
}
|
||||
|
||||
private float getScrimAlpha() {
|
||||
|
||||
@@ -1022,6 +1022,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
|
||||
|
||||
/** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */
|
||||
public void updateStateForSysuiFlags(long systemUiStateFlags, boolean skipAnim) {
|
||||
if (mActivity.isPhoneMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long animDuration = TASKBAR_STASH_DURATION;
|
||||
long startDelay = 0;
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ public class TaskbarUIController {
|
||||
// Initialized in init.
|
||||
protected TaskbarControllers mControllers;
|
||||
|
||||
protected boolean mSkipLauncherVisibilityChange;
|
||||
|
||||
@CallSuper
|
||||
protected void init(TaskbarControllers taskbarControllers) {
|
||||
mControllers = taskbarControllers;
|
||||
@@ -418,4 +420,12 @@ public class TaskbarUIController {
|
||||
public void setUserIsNotGoingHome(boolean isNotGoingHome) {
|
||||
mControllers.taskbarStashController.setUserIsNotGoingHome(isNotGoingHome);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to prevent taskbar from reacting to launcher visibility during the recents
|
||||
* transition animation.
|
||||
*/
|
||||
public void setSkipLauncherVisibilityChange(boolean skip) {
|
||||
mSkipLauncherVisibilityChange = skip;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,8 +669,20 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
|
||||
return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets visual bounds of the taskbar view. The visual bounds correspond to the taskbar touch
|
||||
* area, rather than layout placement in the parent view.
|
||||
*/
|
||||
public Rect getIconLayoutVisualBounds() {
|
||||
return new Rect(mIconLayoutBounds);
|
||||
}
|
||||
|
||||
/** Gets taskbar layout bounds in parent view. */
|
||||
public Rect getIconLayoutBounds() {
|
||||
return mIconLayoutBounds;
|
||||
Rect actualBounds = new Rect(mIconLayoutBounds);
|
||||
actualBounds.top = getTop();
|
||||
actualBounds.bottom = getBottom();
|
||||
return actualBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,7 +96,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4;
|
||||
public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5;
|
||||
public static final int ALPHA_INDEX_SMALL_SCREEN = 6;
|
||||
private static final int NUM_ALPHA_CHANNELS = 7;
|
||||
|
||||
public static final int ALPHA_INDEX_BUBBLE_BAR = 7;
|
||||
private static final int NUM_ALPHA_CHANNELS = 8;
|
||||
|
||||
private static boolean sEnableModelLoadingForTests = true;
|
||||
|
||||
@@ -272,6 +274,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
OneShotPreDrawListener.add(mTaskbarView, listener);
|
||||
}
|
||||
|
||||
public Rect getIconLayoutVisualBounds() {
|
||||
return mTaskbarView.getIconLayoutVisualBounds();
|
||||
}
|
||||
|
||||
public Rect getIconLayoutBounds() {
|
||||
return mTaskbarView.getIconLayoutBounds();
|
||||
}
|
||||
@@ -462,14 +468,14 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
if (mControllers.getSharedState().startTaskbarVariantIsTransient) {
|
||||
float transY =
|
||||
mTransientTaskbarDp.taskbarBottomMargin + (mTransientTaskbarDp.taskbarHeight
|
||||
- mTaskbarView.getIconLayoutBounds().bottom)
|
||||
- mTaskbarView.getIconLayoutVisualBounds().bottom)
|
||||
- (mPersistentTaskbarDp.taskbarHeight
|
||||
- mTransientTaskbarDp.taskbarIconSize) / 2f;
|
||||
taskbarIconTranslationYForPinningValue = mapRange(scale, 0f, transY);
|
||||
} else {
|
||||
float transY =
|
||||
-mTransientTaskbarDp.taskbarBottomMargin + (mPersistentTaskbarDp.taskbarHeight
|
||||
- mTaskbarView.getIconLayoutBounds().bottom)
|
||||
- mTaskbarView.getIconLayoutVisualBounds().bottom)
|
||||
- (mTransientTaskbarDp.taskbarHeight
|
||||
- mTransientTaskbarDp.taskbarIconSize) / 2f;
|
||||
taskbarIconTranslationYForPinningValue = mapRange(scale, transY, 0f);
|
||||
|
||||
@@ -110,7 +110,7 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext) :
|
||||
}
|
||||
|
||||
fun setIsVoiceInteractionWindowVisible(visible: Boolean, skipAnim: Boolean) {
|
||||
if (isVoiceInteractionWindowVisible == visible) {
|
||||
if (isVoiceInteractionWindowVisible == visible || context.isPhoneMode) {
|
||||
return
|
||||
}
|
||||
isVoiceInteractionWindowVisible = visible
|
||||
|
||||
@@ -661,13 +661,25 @@ public class BubbleBarView extends FrameLayout {
|
||||
return displayHeight - bubbleBarHeight + (int) mController.getBubbleBarTranslationY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the bounds with translation that may have been applied and returns the result.
|
||||
*/
|
||||
/** Returns the bounds with translation that may have been applied. */
|
||||
public Rect getBubbleBarBounds() {
|
||||
mBubbleBarBounds.top = getTop() + (int) getTranslationY() + mPointerSize;
|
||||
mBubbleBarBounds.bottom = getBottom() + (int) getTranslationY();
|
||||
return mBubbleBarBounds;
|
||||
Rect bounds = new Rect(mBubbleBarBounds);
|
||||
bounds.top = getTop() + (int) getTranslationY() + mPointerSize;
|
||||
bounds.bottom = getBottom() + (int) getTranslationY();
|
||||
return bounds;
|
||||
}
|
||||
|
||||
/** Returns the expanded bounds with translation that may have been applied. */
|
||||
public Rect getBubbleBarExpandedBounds() {
|
||||
Rect expandedBounds = getBubbleBarBounds();
|
||||
if (!isExpanded() || isExpanding()) {
|
||||
if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
|
||||
expandedBounds.right = expandedBounds.left + (int) expandedWidth();
|
||||
} else {
|
||||
expandedBounds.left = expandedBounds.right - (int) expandedWidth();
|
||||
}
|
||||
}
|
||||
return expandedBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1279,6 +1291,13 @@ public class BubbleBarView extends FrameLayout {
|
||||
return mIsBarExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the bubble bar is expanding.
|
||||
*/
|
||||
public boolean isExpanding() {
|
||||
return mWidthAnimator.isRunning() && mIsBarExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get width of the bubble bar as if it would be expanded.
|
||||
*
|
||||
|
||||
@@ -72,6 +72,7 @@ public class BubbleBarViewController {
|
||||
private BubbleDragController mBubbleDragController;
|
||||
private TaskbarStashController mTaskbarStashController;
|
||||
private TaskbarInsetsController mTaskbarInsetsController;
|
||||
private TaskbarViewPropertiesProvider mTaskbarViewPropertiesProvider;
|
||||
private View.OnClickListener mBubbleClickListener;
|
||||
private View.OnClickListener mBubbleBarClickListener;
|
||||
private BubbleView.Controller mBubbleViewController;
|
||||
@@ -110,13 +111,16 @@ public class BubbleBarViewController {
|
||||
R.dimen.bubblebar_icon_size);
|
||||
}
|
||||
|
||||
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
|
||||
/** Initializes controller. */
|
||||
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers,
|
||||
TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) {
|
||||
mBubbleStashController = bubbleControllers.bubbleStashController;
|
||||
mBubbleBarController = bubbleControllers.bubbleBarController;
|
||||
mBubbleDragController = bubbleControllers.bubbleDragController;
|
||||
mTaskbarStashController = controllers.taskbarStashController;
|
||||
mTaskbarInsetsController = controllers.taskbarInsetsController;
|
||||
mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
|
||||
mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
|
||||
onBubbleBarConfigurationChanged(/* animate= */ false);
|
||||
mActivity.addOnDeviceProfileChangeListener(
|
||||
dp -> onBubbleBarConfigurationChanged(/* animate= */ true));
|
||||
@@ -348,6 +352,7 @@ public class BubbleBarViewController {
|
||||
if (hidden) {
|
||||
mBarView.setAlpha(0);
|
||||
mBarView.setExpanded(false);
|
||||
updatePersistentTaskbar(/* isBubbleBarExpanded = */ false);
|
||||
}
|
||||
mActivity.bubbleBarVisibilityChanged(!hidden);
|
||||
}
|
||||
@@ -612,6 +617,7 @@ public class BubbleBarViewController {
|
||||
public void setExpanded(boolean isExpanded) {
|
||||
if (isExpanded != mBarView.isExpanded()) {
|
||||
mBarView.setExpanded(isExpanded);
|
||||
updatePersistentTaskbar(isExpanded);
|
||||
if (!isExpanded) {
|
||||
mSystemUiProxy.collapseBubbles();
|
||||
} else {
|
||||
@@ -622,6 +628,25 @@ public class BubbleBarViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePersistentTaskbar(boolean isBubbleBarExpanded) {
|
||||
if (mBubbleStashController.isTransientTaskBar()) return;
|
||||
boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar();
|
||||
mTaskbarViewPropertiesProvider
|
||||
.getIconsAlpha()
|
||||
.animateToValue(hideTaskbar ? 0 : 1)
|
||||
.start();
|
||||
}
|
||||
|
||||
/** Return {@code true} if expanded bubble bar would intersect the taskbar. */
|
||||
public boolean isIntersectingTaskbar() {
|
||||
if (mBarView.isExpanding() || mBarView.isExpanded()) {
|
||||
Rect taskbarViewBounds = mTaskbarViewPropertiesProvider.getTaskbarViewBounds();
|
||||
return mBarView.getBubbleBarExpandedBounds().intersect(taskbarViewBounds);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the bubble bar should be expanded. This method is used in response to UI events
|
||||
* from SystemUI.
|
||||
@@ -755,4 +780,14 @@ public class BubbleBarViewController {
|
||||
pw.println(" Bubble bar view is null!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Interface for BubbleBarViewController to get the taskbar view properties. */
|
||||
public interface TaskbarViewPropertiesProvider {
|
||||
|
||||
/** Returns the bounds of the taskbar. */
|
||||
Rect getTaskbarViewBounds();
|
||||
|
||||
/** Returns taskbar icons alpha */
|
||||
MultiPropertyFactory<View>.MultiProperty getIconsAlpha();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,15 @@
|
||||
*/
|
||||
package com.android.launcher3.taskbar.bubbles;
|
||||
|
||||
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_BUBBLE_BAR;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.taskbar.TaskbarControllers;
|
||||
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController.TaskbarViewPropertiesProvider;
|
||||
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
|
||||
import com.android.launcher3.util.MultiPropertyFactory;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -79,7 +86,20 @@ public class BubbleControllers {
|
||||
bubbleStashedHandleViewController.orElse(null),
|
||||
taskbarControllers::runAfterInit
|
||||
);
|
||||
bubbleBarViewController.init(taskbarControllers, /* bubbleControllers = */ this);
|
||||
bubbleBarViewController.init(taskbarControllers, /* bubbleControllers = */ this,
|
||||
new TaskbarViewPropertiesProvider() {
|
||||
@Override
|
||||
public Rect getTaskbarViewBounds() {
|
||||
return taskbarControllers.taskbarViewController.getIconLayoutBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiPropertyFactory<View>.MultiProperty getIconsAlpha() {
|
||||
return taskbarControllers.taskbarViewController
|
||||
.getTaskbarIconAlpha()
|
||||
.get(ALPHA_INDEX_BUBBLE_BAR);
|
||||
}
|
||||
});
|
||||
bubbleDragController.init(/* bubbleControllers = */ this);
|
||||
bubbleDismissController.init(/* bubbleControllers = */ this);
|
||||
bubbleBarPinController.init(this);
|
||||
|
||||
@@ -45,6 +45,7 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
|
||||
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
|
||||
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
|
||||
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
|
||||
import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT;
|
||||
import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP;
|
||||
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
|
||||
import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL;
|
||||
@@ -75,6 +76,7 @@ import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
@@ -215,7 +217,8 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class QuickstepLauncher extends Launcher implements RecentsViewContainer {
|
||||
public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
|
||||
SystemShortcut.BubbleActivityStarter {
|
||||
private static final boolean TRACE_LAYOUTS =
|
||||
SystemProperties.getBoolean("persist.debug.trace_layouts", false);
|
||||
private static final String TRACE_RELAYOUT_CLASS =
|
||||
@@ -466,6 +469,9 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer
|
||||
if (Flags.enablePrivateSpace()) {
|
||||
shortcuts.add(UNINSTALL_APP);
|
||||
}
|
||||
if (com.android.wm.shell.Flags.enableBubbleAnything()) {
|
||||
shortcuts.add(BUBBLE_SHORTCUT);
|
||||
}
|
||||
return shortcuts.stream();
|
||||
}
|
||||
|
||||
@@ -1436,6 +1442,18 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showShortcutBubble(ShortcutInfo info) {
|
||||
if (info == null) return;
|
||||
SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showAppBubble(Intent intent) {
|
||||
if (intent == null || intent.getPackage() == null) return;
|
||||
SystemUiProxy.INSTANCE.get(this).showAppBubble(intent);
|
||||
}
|
||||
|
||||
private static final class LauncherTaskViewController extends
|
||||
TaskViewTouchController<QuickstepLauncher> {
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ import android.view.IRecentsAnimationController;
|
||||
import android.view.IRecentsAnimationRunner;
|
||||
import android.view.IRemoteAnimationRunner;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
import android.window.IOnBackInvokedCallback;
|
||||
@@ -894,6 +893,36 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells SysUI to show a shortcut bubble.
|
||||
*
|
||||
* @param info the shortcut info used to create or identify the bubble.
|
||||
*/
|
||||
public void showShortcutBubble(ShortcutInfo info) {
|
||||
try {
|
||||
if (mBubbles != null) {
|
||||
mBubbles.showShortcutBubble(info);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed call show bubble for shortcut");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells SysUI to show a bubble of an app.
|
||||
*
|
||||
* @param intent the intent used to create the bubble.
|
||||
*/
|
||||
public void showAppBubble(Intent intent) {
|
||||
try {
|
||||
if (mBubbles != null) {
|
||||
mBubbles.showAppBubble(intent);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed call show bubble for app");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Splitscreen
|
||||
//
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.quickstep;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
|
||||
import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
|
||||
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
|
||||
@@ -44,6 +45,7 @@ import androidx.annotation.UiThread;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.taskbar.TaskbarUIController;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.SystemUiFlagUtils;
|
||||
@@ -334,6 +336,28 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
options.setTransientLaunch();
|
||||
}
|
||||
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
|
||||
|
||||
// Notify taskbar that we should skip reacting to launcher visibility change to
|
||||
// avoid a jumping taskbar.
|
||||
TaskbarUIController taskbarUIController = containerInterface.getTaskbarController();
|
||||
if (enableScalingRevealHomeAnimation() && taskbarUIController != null) {
|
||||
taskbarUIController.setSkipLauncherVisibilityChange(true);
|
||||
|
||||
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
|
||||
@Override
|
||||
public void onRecentsAnimationCanceled(
|
||||
@NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {
|
||||
taskbarUIController.setSkipLauncherVisibilityChange(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationFinished(
|
||||
@NonNull RecentsAnimationController controller) {
|
||||
taskbarUIController.setSkipLauncherVisibilityChange(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mRecentsAnimationStartPending = getSystemUiProxy()
|
||||
.startRecentsActivity(intent, options, mCallbacks);
|
||||
if (enableHandleDelayedGestureCallbacks()) {
|
||||
|
||||
@@ -836,7 +836,7 @@ public class SplitSelectStateController {
|
||||
private final int mSplitPlaceholderSize;
|
||||
private final int mSplitPlaceholderInset;
|
||||
private ActivityManager.RunningTaskInfo mTaskInfo;
|
||||
private ISplitSelectListener mSplitSelectListener;
|
||||
private DesktopSplitSelectListenerImpl mSplitSelectListener;
|
||||
private Drawable mAppIcon;
|
||||
|
||||
public SplitFromDesktopController(QuickstepLauncher launcher,
|
||||
@@ -847,21 +847,14 @@ public class SplitSelectStateController {
|
||||
R.dimen.split_placeholder_size);
|
||||
mSplitPlaceholderInset = mLauncher.getResources().getDimensionPixelSize(
|
||||
R.dimen.split_placeholder_inset);
|
||||
mSplitSelectListener = new ISplitSelectListener.Stub() {
|
||||
@Override
|
||||
public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
|
||||
int splitPosition, Rect taskBounds) {
|
||||
MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo, splitPosition,
|
||||
taskBounds));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
mSplitSelectListener = new DesktopSplitSelectListenerImpl(this);
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).registerSplitSelectListener(mSplitSelectListener);
|
||||
}
|
||||
|
||||
void onDestroy() {
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).unregisterSplitSelectListener(
|
||||
mSplitSelectListener);
|
||||
mSplitSelectListener.release();
|
||||
mSplitSelectListener = null;
|
||||
}
|
||||
|
||||
@@ -954,4 +947,35 @@ public class SplitSelectStateController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for the ISplitSelectListener stub to prevent lingering references to the launcher
|
||||
* activity via the controller.
|
||||
*/
|
||||
private static class DesktopSplitSelectListenerImpl extends ISplitSelectListener.Stub {
|
||||
|
||||
private SplitFromDesktopController mController;
|
||||
|
||||
DesktopSplitSelectListenerImpl(@NonNull SplitFromDesktopController controller) {
|
||||
mController = controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any references to the controller.
|
||||
*/
|
||||
void release() {
|
||||
mController = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
|
||||
int splitPosition, Rect taskBounds) {
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
if (mController != null) {
|
||||
mController.enterSplitSelect(taskInfo, splitPosition, taskBounds);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ import com.android.launcher3.BuildConfig
|
||||
import com.android.launcher3.ui.AbstractLauncherUiTest
|
||||
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape
|
||||
import com.android.launcher3.uioverrides.QuickstepLauncher
|
||||
import com.android.launcher3.util.rule.TestStabilityRule
|
||||
import com.android.launcher3.util.rule.TestStabilityRule.LOCAL
|
||||
import com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT
|
||||
import com.google.common.truth.Truth.assertWithMessage
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@@ -42,6 +45,7 @@ class TaplTestsOverviewDesktop : AbstractLauncherUiTest<QuickstepLauncher?>() {
|
||||
mLauncher.goHome()
|
||||
}
|
||||
|
||||
@TestStabilityRule.Stability(flavors = LOCAL or PLATFORM_POSTSUBMIT)
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
fun enterDesktopViaOverviewMenu() {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2024 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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
|
||||
</vector>
|
||||
@@ -215,7 +215,8 @@
|
||||
<string name="dismiss_prediction_label">Don\'t suggest app</string>
|
||||
<!-- Label for pinning predicted app. -->
|
||||
<string name="pin_prediction">Pin Prediction</string>
|
||||
|
||||
<!-- Label for bubbling a launcher item. [CHAR_LIMIT=20] -->
|
||||
<string name="bubble">Bubble</string>
|
||||
|
||||
<!-- Permissions: -->
|
||||
<skip />
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
@@ -97,6 +98,8 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon {
|
||||
|
||||
public int options;
|
||||
|
||||
@Nullable
|
||||
private ShortcutInfo mShortcutInfo = null;
|
||||
|
||||
public WorkspaceItemInfo() {
|
||||
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
@@ -175,6 +178,9 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon {
|
||||
|
||||
public void updateFromDeepShortcutInfo(@NonNull final ShortcutInfo shortcutInfo,
|
||||
@NonNull final Context context) {
|
||||
if (com.android.wm.shell.Flags.enableBubbleAnything()) {
|
||||
mShortcutInfo = shortcutInfo;
|
||||
}
|
||||
// {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent
|
||||
intent = ShortcutKey.makeIntent(shortcutInfo);
|
||||
title = shortcutInfo.getShortLabel();
|
||||
@@ -204,6 +210,11 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon {
|
||||
: Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ShortcutInfo getDeepShortcutInfo() {
|
||||
return mShortcutInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code true} if the shortcut is disabled due to its app being a lower version.
|
||||
*/
|
||||
|
||||
@@ -11,9 +11,11 @@ import android.app.ActivityOptions;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.ImageView;
|
||||
@@ -25,6 +27,7 @@ import androidx.annotation.Nullable;
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.AbstractFloatingViewHelper;
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.SecondaryDropTarget;
|
||||
import com.android.launcher3.Utilities;
|
||||
@@ -53,6 +56,7 @@ import java.util.Arrays;
|
||||
*/
|
||||
public abstract class SystemShortcut<T extends ActivityContext> extends ItemInfo
|
||||
implements View.OnClickListener {
|
||||
private static final String TAG = "SystemShortcut";
|
||||
|
||||
private final int mIconResId;
|
||||
protected final int mLabelResId;
|
||||
@@ -383,4 +387,63 @@ public abstract class SystemShortcut<T extends ActivityContext> extends ItemInfo
|
||||
mAbstractFloatingViewHelper.closeOpenViews(mTarget, true,
|
||||
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
|
||||
}
|
||||
|
||||
public static final Factory<ActivityContext> BUBBLE_SHORTCUT =
|
||||
(activity, itemInfo, originalView) -> {
|
||||
if ((itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
|
||||
&& (itemInfo.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION)
|
||||
&& !(itemInfo instanceof WorkspaceItemInfo)) {
|
||||
return null;
|
||||
}
|
||||
return new BubbleShortcut(activity, itemInfo, originalView);
|
||||
};
|
||||
|
||||
public interface BubbleActivityStarter {
|
||||
/** Tell SysUI to show the provided shortcut in a bubble. */
|
||||
void showShortcutBubble(ShortcutInfo info);
|
||||
|
||||
/** Tell SysUI to show the provided intent in a bubble. */
|
||||
void showAppBubble(Intent intent);
|
||||
}
|
||||
|
||||
public static class BubbleShortcut<T extends ActivityContext> extends SystemShortcut<T> {
|
||||
|
||||
private BubbleActivityStarter mStarter;
|
||||
|
||||
public BubbleShortcut(T target, ItemInfo itemInfo, View originalView) {
|
||||
super(R.drawable.ic_bubble_button, R.string.bubble, target,
|
||||
itemInfo, originalView);
|
||||
if (target instanceof BubbleActivityStarter) {
|
||||
mStarter = (BubbleActivityStarter) target;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
dismissTaskMenuView();
|
||||
if (mStarter == null) {
|
||||
Log.w(TAG, "starter null!");
|
||||
return;
|
||||
}
|
||||
// TODO: handle GroupTask (single) items so that recent items in taskbar work
|
||||
if (mItemInfo instanceof WorkspaceItemInfo) {
|
||||
WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) mItemInfo;
|
||||
ShortcutInfo shortcutInfo = workspaceItemInfo.getDeepShortcutInfo();
|
||||
if (shortcutInfo != null) {
|
||||
mStarter.showShortcutBubble(shortcutInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If we're here check for an intent
|
||||
Intent intent = mItemInfo.getIntent();
|
||||
if (intent != null) {
|
||||
if (intent.getPackage() == null) {
|
||||
intent.setPackage(mItemInfo.getTargetPackage());
|
||||
}
|
||||
mStarter.showAppBubble(intent);
|
||||
} else {
|
||||
Log.w(TAG, "unable to bubble, no intent: " + mItemInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user