Loading core/java/android/content/ClipDescription.java +18 −1 Original line number Diff line number Diff line Loading @@ -64,11 +64,28 @@ public class ClipDescription implements Parcelable { public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"; /** * The MIME type for an activity. * The MIME type for an activity. The ClipData must include intents with required extras * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional * {@link #EXTRA_ACTIVITY_OPTIONS}. * @hide */ public static final String MIMETYPE_APPLICATION_ACTIVITY = "application/vnd.android.activity"; /** * The MIME type for a shortcut. The ClipData must include intents with required extras * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional * {@link #EXTRA_ACTIVITY_OPTIONS}. * @hide */ public static final String MIMETYPE_APPLICATION_SHORTCUT = "application/vnd.android.shortcut"; /** * The MIME type for a task. The ClipData must include an intent with a required extra * {@link Intent#EXTRA_TASK_ID} of the task to launch. * @hide */ public static final String MIMETYPE_APPLICATION_TASK = "application/vnd.android.task"; /** * The MIME type for data whose type is otherwise unknown. * <p> Loading core/java/android/content/pm/ILauncherApps.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.content.pm; import android.app.IApplicationThread; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; Loading Loading @@ -55,6 +56,8 @@ interface ILauncherApps { void startActivityAsUser(in IApplicationThread caller, String callingPackage, String callingFeatureId, in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); PendingIntent getActivityLaunchIntent(in ComponentName component, in Bundle opts, in UserHandle user); void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage, String callingFeatureId, in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); Loading core/java/android/content/pm/LauncherApps.java +24 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.content.pm; import static android.Manifest.permission; import static android.app.PendingIntent.FLAG_IMMUTABLE; import android.annotation.CallbackExecutor; import android.annotation.IntDef; Loading Loading @@ -715,6 +716,29 @@ public class LauncherApps { } } /** * Returns a PendingIntent that would start the same activity started from * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}. * * @param component The ComponentName of the activity to launch * @param startActivityOptions Options to pass to startActivity * @param user The UserHandle of the profile * @hide */ @Nullable public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component, @Nullable Bundle startActivityOptions, @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); if (DEBUG) { Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user); } try { return mService.getActivityLaunchIntent(component, startActivityOptions, user); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it * returns null. Loading libs/WindowManager/Shell/res/raw/wm_shell_protolog.json +6 −0 Original line number Diff line number Diff line Loading @@ -169,6 +169,12 @@ "group": "WM_SHELL_DRAG_AND_DROP", "at": "com\/android\/wm\/shell\/draganddrop\/DragLayout.java" }, "1842752748": { "message": "Clip description: handlingDrag=%b mimeTypes=%s", "level": "VERBOSE", "group": "WM_SHELL_DRAG_AND_DROP", "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java" }, "1862198614": { "message": "Drag event: action=%s x=%f y=%f xOffset=%f yOffset=%f", "level": "VERBOSE", Loading libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +85 −30 Original line number Diff line number Diff line Loading @@ -16,8 +16,17 @@ package com.android.wm.shell.draganddrop; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS; import static android.content.ClipDescription.EXTRA_PENDING_INTENT; import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY; import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK; import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.EXTRA_SHORTCUT_ID; import static android.content.Intent.EXTRA_TASK_ID; import static android.content.Intent.EXTRA_USER; import static android.view.DragEvent.ACTION_DRAG_ENDED; import static android.view.DragEvent.ACTION_DRAG_ENTERED; import static android.view.DragEvent.ACTION_DRAG_EXITED; Loading @@ -33,15 +42,24 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ClipDescription; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; import android.view.DragEvent; Loading @@ -68,6 +86,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private static final String TAG = DragAndDropController.class.getSimpleName(); private final Context mContext; private final DisplayController mDisplayController; private SplitScreen mSplitScreen; Loading @@ -76,7 +95,8 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private DragLayout mDragLayout; private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); public DragAndDropController(DisplayController displayController) { public DragAndDropController(Context context, DisplayController displayController) { mContext = context; mDisplayController = displayController; mDisplayController.addDisplayWindowListener(this); } Loading Loading @@ -135,13 +155,16 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange event.getOffsetX(), event.getOffsetY()); final int displayId = target.getDisplay().getDisplayId(); final PerDisplay pd = mDisplayDropTargets.get(displayId); final ClipDescription description = event.getClipDescription(); if (event.getAction() == ACTION_DRAG_STARTED) { final ClipDescription description = event.getClipDescription(); final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY); final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY) || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT) || description.hasMimeType(MIMETYPE_APPLICATION_TASK); mIsHandlingDrag = hasValidClipData; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Clip description: %s", getMimeTypes(description)); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Clip description: handlingDrag=%b mimeTypes=%s", mIsHandlingDrag, getMimeTypes(description)); } if (!mIsHandlingDrag) { Loading @@ -163,31 +186,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange mDragLayout.update(event); break; case ACTION_DROP: { final SurfaceControl dragSurface = event.getDragSurface(); final View dragLayout = mDragLayout; final ClipData data = event.getClipData(); return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> { if (dropTargetBounds != null) { // TODO(b/169894807): Properly handle the drop, for now just launch it if (data.getItemCount() > 0) { Intent intent = data.getItemAt(0).getIntent(); PendingIntent pi = intent.getParcelableExtra( ClipDescription.EXTRA_PENDING_INTENT); try { pi.send(); } catch (PendingIntent.CanceledException e) { Slog.e(TAG, "Failed to launch activity", e); } } } setDropTargetWindowVisibility(pd, View.INVISIBLE); pd.dropTarget.removeView(dragLayout); // Clean up the drag surface mTransaction.reparent(dragSurface, null); mTransaction.apply(); }); return handleDrop(event, pd); } case ACTION_DRAG_EXITED: { // Either one of DROP or EXITED will happen, and when EXITED we won't consume Loading @@ -211,6 +210,62 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange return true; } /** * Handles dropping on the drop target. */ private boolean handleDrop(DragEvent event, PerDisplay pd) { final ClipData data = event.getClipData(); final ClipDescription description = event.getClipDescription(); final SurfaceControl dragSurface = event.getDragSurface(); final View dragLayout = mDragLayout; final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> { if (dropTargetBounds != null && data.getItemCount() > 0) { final Intent intent = data.getItemAt(0).getIntent(); // TODO(b/169894807): Properly handle the drop, for now just launch it if (isTask) { int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); try { ActivityTaskManager.getService().startActivityFromRecents( taskId, null); } catch (RemoteException e) { Slog.e(TAG, "Failed to launch task", e); } } else if (isShortcut) { try { Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS) ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : null; LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); launcherApps.startShortcut( intent.getStringExtra(EXTRA_PACKAGE_NAME), intent.getStringExtra(EXTRA_SHORTCUT_ID), null /* sourceBounds */, opts, intent.getParcelableExtra(EXTRA_USER)); } catch (ActivityNotFoundException e) { Slog.e(TAG, "Failed to launch shortcut", e); } } else { PendingIntent pi = intent.getParcelableExtra(EXTRA_PENDING_INTENT); try { pi.send(); } catch (PendingIntent.CanceledException e) { Slog.e(TAG, "Failed to launch activity", e); } } } setDropTargetWindowVisibility(pd, View.INVISIBLE); pd.dropTarget.removeView(dragLayout); // Clean up the drag surface mTransaction.reparent(dragSurface, null); mTransaction.apply(); }); } private void setDropTargetWindowVisibility(PerDisplay pd, int visibility) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Set drop target window visibility: displayId=%d visibility=%d", Loading Loading
core/java/android/content/ClipDescription.java +18 −1 Original line number Diff line number Diff line Loading @@ -64,11 +64,28 @@ public class ClipDescription implements Parcelable { public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"; /** * The MIME type for an activity. * The MIME type for an activity. The ClipData must include intents with required extras * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional * {@link #EXTRA_ACTIVITY_OPTIONS}. * @hide */ public static final String MIMETYPE_APPLICATION_ACTIVITY = "application/vnd.android.activity"; /** * The MIME type for a shortcut. The ClipData must include intents with required extras * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional * {@link #EXTRA_ACTIVITY_OPTIONS}. * @hide */ public static final String MIMETYPE_APPLICATION_SHORTCUT = "application/vnd.android.shortcut"; /** * The MIME type for a task. The ClipData must include an intent with a required extra * {@link Intent#EXTRA_TASK_ID} of the task to launch. * @hide */ public static final String MIMETYPE_APPLICATION_TASK = "application/vnd.android.task"; /** * The MIME type for data whose type is otherwise unknown. * <p> Loading
core/java/android/content/pm/ILauncherApps.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.content.pm; import android.app.IApplicationThread; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; Loading Loading @@ -55,6 +56,8 @@ interface ILauncherApps { void startActivityAsUser(in IApplicationThread caller, String callingPackage, String callingFeatureId, in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); PendingIntent getActivityLaunchIntent(in ComponentName component, in Bundle opts, in UserHandle user); void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage, String callingFeatureId, in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); Loading
core/java/android/content/pm/LauncherApps.java +24 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.content.pm; import static android.Manifest.permission; import static android.app.PendingIntent.FLAG_IMMUTABLE; import android.annotation.CallbackExecutor; import android.annotation.IntDef; Loading Loading @@ -715,6 +716,29 @@ public class LauncherApps { } } /** * Returns a PendingIntent that would start the same activity started from * {@link #startMainActivity(ComponentName, UserHandle, Rect, Bundle)}. * * @param component The ComponentName of the activity to launch * @param startActivityOptions Options to pass to startActivity * @param user The UserHandle of the profile * @hide */ @Nullable public PendingIntent getMainActivityLaunchIntent(@NonNull ComponentName component, @Nullable Bundle startActivityOptions, @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); if (DEBUG) { Log.i(TAG, "GetMainActivityLaunchIntent " + component + " " + user); } try { return mService.getActivityLaunchIntent(component, startActivityOptions, user); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } /** * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it * returns null. Loading
libs/WindowManager/Shell/res/raw/wm_shell_protolog.json +6 −0 Original line number Diff line number Diff line Loading @@ -169,6 +169,12 @@ "group": "WM_SHELL_DRAG_AND_DROP", "at": "com\/android\/wm\/shell\/draganddrop\/DragLayout.java" }, "1842752748": { "message": "Clip description: handlingDrag=%b mimeTypes=%s", "level": "VERBOSE", "group": "WM_SHELL_DRAG_AND_DROP", "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java" }, "1862198614": { "message": "Drag event: action=%s x=%f y=%f xOffset=%f yOffset=%f", "level": "VERBOSE", Loading
libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +85 −30 Original line number Diff line number Diff line Loading @@ -16,8 +16,17 @@ package com.android.wm.shell.draganddrop; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS; import static android.content.ClipDescription.EXTRA_PENDING_INTENT; import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY; import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK; import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.EXTRA_SHORTCUT_ID; import static android.content.Intent.EXTRA_TASK_ID; import static android.content.Intent.EXTRA_USER; import static android.view.DragEvent.ACTION_DRAG_ENDED; import static android.view.DragEvent.ACTION_DRAG_ENTERED; import static android.view.DragEvent.ACTION_DRAG_EXITED; Loading @@ -33,15 +42,24 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ClipDescription; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; import android.view.DragEvent; Loading @@ -68,6 +86,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private static final String TAG = DragAndDropController.class.getSimpleName(); private final Context mContext; private final DisplayController mDisplayController; private SplitScreen mSplitScreen; Loading @@ -76,7 +95,8 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange private DragLayout mDragLayout; private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); public DragAndDropController(DisplayController displayController) { public DragAndDropController(Context context, DisplayController displayController) { mContext = context; mDisplayController = displayController; mDisplayController.addDisplayWindowListener(this); } Loading Loading @@ -135,13 +155,16 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange event.getOffsetX(), event.getOffsetY()); final int displayId = target.getDisplay().getDisplayId(); final PerDisplay pd = mDisplayDropTargets.get(displayId); final ClipDescription description = event.getClipDescription(); if (event.getAction() == ACTION_DRAG_STARTED) { final ClipDescription description = event.getClipDescription(); final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY); final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY) || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT) || description.hasMimeType(MIMETYPE_APPLICATION_TASK); mIsHandlingDrag = hasValidClipData; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Clip description: %s", getMimeTypes(description)); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Clip description: handlingDrag=%b mimeTypes=%s", mIsHandlingDrag, getMimeTypes(description)); } if (!mIsHandlingDrag) { Loading @@ -163,31 +186,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange mDragLayout.update(event); break; case ACTION_DROP: { final SurfaceControl dragSurface = event.getDragSurface(); final View dragLayout = mDragLayout; final ClipData data = event.getClipData(); return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> { if (dropTargetBounds != null) { // TODO(b/169894807): Properly handle the drop, for now just launch it if (data.getItemCount() > 0) { Intent intent = data.getItemAt(0).getIntent(); PendingIntent pi = intent.getParcelableExtra( ClipDescription.EXTRA_PENDING_INTENT); try { pi.send(); } catch (PendingIntent.CanceledException e) { Slog.e(TAG, "Failed to launch activity", e); } } } setDropTargetWindowVisibility(pd, View.INVISIBLE); pd.dropTarget.removeView(dragLayout); // Clean up the drag surface mTransaction.reparent(dragSurface, null); mTransaction.apply(); }); return handleDrop(event, pd); } case ACTION_DRAG_EXITED: { // Either one of DROP or EXITED will happen, and when EXITED we won't consume Loading @@ -211,6 +210,62 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange return true; } /** * Handles dropping on the drop target. */ private boolean handleDrop(DragEvent event, PerDisplay pd) { final ClipData data = event.getClipData(); final ClipDescription description = event.getClipDescription(); final SurfaceControl dragSurface = event.getDragSurface(); final View dragLayout = mDragLayout; final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> { if (dropTargetBounds != null && data.getItemCount() > 0) { final Intent intent = data.getItemAt(0).getIntent(); // TODO(b/169894807): Properly handle the drop, for now just launch it if (isTask) { int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); try { ActivityTaskManager.getService().startActivityFromRecents( taskId, null); } catch (RemoteException e) { Slog.e(TAG, "Failed to launch task", e); } } else if (isShortcut) { try { Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS) ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : null; LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); launcherApps.startShortcut( intent.getStringExtra(EXTRA_PACKAGE_NAME), intent.getStringExtra(EXTRA_SHORTCUT_ID), null /* sourceBounds */, opts, intent.getParcelableExtra(EXTRA_USER)); } catch (ActivityNotFoundException e) { Slog.e(TAG, "Failed to launch shortcut", e); } } else { PendingIntent pi = intent.getParcelableExtra(EXTRA_PENDING_INTENT); try { pi.send(); } catch (PendingIntent.CanceledException e) { Slog.e(TAG, "Failed to launch activity", e); } } } setDropTargetWindowVisibility(pd, View.INVISIBLE); pd.dropTarget.removeView(dragLayout); // Clean up the drag surface mTransaction.reparent(dragSurface, null); mTransaction.apply(); }); } private void setDropTargetWindowVisibility(PerDisplay pd, int visibility) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Set drop target window visibility: displayId=%d visibility=%d", Loading