Merge "Add a bubble option to launcher long press menus" into main
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
//
|
||||
|
||||
@@ -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