Merge "Moving autority definition to a separate file, so that it can be easily customized using android studio" into ub-launcher3-master
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 5810e8b..1af9e8d 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index c712703..08132aa 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -26,6 +26,8 @@
     <string name="recent_task_option_split_screen">Split screen</string>
     <!-- Title for an option to keep an app pinned to the screen until it is unpinned -->
     <string name="recent_task_option_pin">Pin</string>
+    <!-- Title for an option to enter freeform mode for a given app -->
+    <string name="recent_task_option_freeform">Freeform</string>
 
     <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_recent_apps">Overview</string>
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 59a937f..cb214af 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -46,6 +46,7 @@
             new TaskSystemShortcut.SplitScreen(),
             new TaskSystemShortcut.Pin(),
             new TaskSystemShortcut.Install(),
+            new TaskSystemShortcut.Freeform()
     };
 
     public static TaskOverlayFactory get(Context context) {
diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
index a8eb321..8b01e59 100644
--- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
 
+import android.app.ActivityOptions;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -33,6 +34,8 @@
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.popup.SystemShortcut;
@@ -102,19 +105,23 @@
         }
     }
 
-    public static class SplitScreen extends TaskSystemShortcut {
+    public static abstract class MultiWindow extends TaskSystemShortcut {
 
         private Handler mHandler;
 
-        public SplitScreen() {
-            super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen);
+        public MultiWindow(int iconRes, int textRes) {
+            super(iconRes, textRes);
             mHandler = new Handler(Looper.getMainLooper());
         }
 
+        protected abstract boolean isAvailable(BaseDraggingActivity activity);
+        protected abstract ActivityOptions makeLaunchOptions();
+        protected abstract boolean onActivityStarted(BaseDraggingActivity activity);
+
         @Override
         public View.OnClickListener getOnClickListener(
                 BaseDraggingActivity activity, TaskView taskView) {
-            if (activity.getDeviceProfile().isMultiWindowMode) {
+            if (!isAvailable(activity)) {
                 return null;
             }
             final Task task  = taskView.getTask();
@@ -153,22 +160,13 @@
 
                 dismissTaskMenuView(activity);
 
-                final int navBarPosition = WindowManagerWrapper.getInstance().getNavBarPosition();
-                if (navBarPosition == WindowManagerWrapper.NAV_BAR_POS_INVALID) {
-                    return;
-                }
-                boolean dockTopOrLeft = navBarPosition != WindowManagerWrapper.NAV_BAR_POS_LEFT;
-                if (ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId,
-                        ActivityOptionsCompat.makeSplitScreenOptions(dockTopOrLeft))) {
-                    ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
-                    try {
-                        sysUiProxy.onSplitScreenInvoked();
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Failed to notify SysUI of split screen: ", e);
+                ActivityOptions options = makeLaunchOptions();
+                if (options != null
+                        && ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId,
+                                options)) {
+                    if (!onActivityStarted(activity)) {
                         return;
                     }
-                    activity.getUserEventDispatcher().logActionOnControl(TAP,
-                            LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET);
                     // Add a device profile change listener to kick off animating the side tasks
                     // once we enter multiwindow mode and relayout
                     activity.addOnDeviceProfileChangeListener(onDeviceProfileChangeListener);
@@ -211,6 +209,64 @@
         }
     }
 
+    public static class SplitScreen extends MultiWindow {
+        public SplitScreen() {
+            super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen);
+        }
+
+        @Override
+        protected boolean isAvailable(BaseDraggingActivity activity) {
+            // Don't show menu-item if already in multi-window
+            return !activity.getDeviceProfile().isMultiWindowMode;
+        }
+
+        @Override
+        protected ActivityOptions makeLaunchOptions() {
+            final int navBarPosition = WindowManagerWrapper.getInstance().getNavBarPosition();
+            if (navBarPosition == WindowManagerWrapper.NAV_BAR_POS_INVALID) {
+                return null;
+            }
+            boolean dockTopOrLeft = navBarPosition != WindowManagerWrapper.NAV_BAR_POS_LEFT;
+            return ActivityOptionsCompat.makeSplitScreenOptions(dockTopOrLeft);
+        }
+
+        @Override
+        protected boolean onActivityStarted(BaseDraggingActivity activity) {
+            ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
+            try {
+                sysUiProxy.onSplitScreenInvoked();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to notify SysUI of split screen: ", e);
+                return false;
+            }
+            activity.getUserEventDispatcher().logActionOnControl(TAP,
+                    LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET);
+            return true;
+        }
+    }
+
+    public static class Freeform extends MultiWindow {
+        public Freeform() {
+            super(R.drawable.ic_split_screen, R.string.recent_task_option_freeform);
+        }
+
+        @Override
+        protected boolean isAvailable(BaseDraggingActivity activity) {
+            return ActivityManagerWrapper.getInstance().supportsFreeformMultiWindow(activity);
+        }
+
+        @Override
+        protected ActivityOptions makeLaunchOptions() {
+            return ActivityOptionsCompat.makeFreeformOptions();
+        }
+
+        @Override
+        protected boolean onActivityStarted(BaseDraggingActivity activity) {
+            Launcher.getLauncher(activity).getStateManager().goToState(LauncherState.NORMAL);
+            return true;
+        }
+    }
+
     public static class Pin extends TaskSystemShortcut {
 
         private static final String TAG = Pin.class.getSimpleName();
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/system_shortcut_icons.xml
index 4daf469..a340f4f 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/system_shortcut_icons.xml
@@ -22,4 +22,10 @@
     android:orientation="horizontal"
     android:gravity="end|center_vertical"
     android:background="?attr/popupColorSecondary"
-    android:clipToPadding="true" />
+    android:clipToPadding="true">
+
+    <Space android:layout_width="0dp"
+           android:layout_height="match_parent"
+           android:layout_weight="1"
+           android:id="@+id/separator"/>
+</LinearLayout>
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 0bb5e2a..ccc15f1 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -126,6 +126,12 @@
         return (T) view;
     }
 
+    public <T extends View> T inflateAndAdd(int resId, ViewGroup container, int index) {
+        View view = mInflater.inflate(resId, container, false);
+        container.addView(view, index);
+        return (T) view;
+    }
+
     /**
      * Called when all view inflation and reordering in complete.
      */
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 12319f7..37a000d 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -391,7 +391,8 @@
     }
 
     private void initializeSystemShortcut(int resId, ViewGroup container, SystemShortcut info) {
-        View view = inflateAndAdd(resId, container);
+        View view = inflateAndAdd(
+                resId, container, getInsertIndexForSystemShortcut(container, info));
         if (view instanceof DeepShortcutView) {
             // Expanded system shortcut, with both icon and text shown on white background.
             final DeepShortcutView shortcutView = (DeepShortcutView) view;
@@ -406,6 +407,17 @@
     }
 
     /**
+     * Returns an index for inserting a shortcut into a container.
+     */
+    private int getInsertIndexForSystemShortcut(ViewGroup container, SystemShortcut shortcut) {
+        final View separator = container.findViewById(R.id.separator);
+
+        return separator != null && shortcut.isLeftGroup() ?
+                container.indexOfChild(separator) :
+                container.getChildCount();
+    }
+
+    /**
      * Determines when the deferred drag should be started.
      *
      * Current behavior:
diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java
index c76fb96..3e12429 100644
--- a/src/com/android/launcher3/popup/RemoteActionShortcut.java
+++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java
@@ -76,4 +76,9 @@
                     LauncherLogProto.ControlType.REMOTE_ACTION_SHORTCUT, view);
         };
     }
+
+    @Override
+    public boolean isLeftGroup() {
+        return true;
+    }
 }
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index f9a2007..fdc1b39 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -71,6 +71,13 @@
         mAccessibilityActionId = other.mAccessibilityActionId;
     }
 
+    /**
+     * Should be in the left group of icons in app's context menu header.
+     */
+    public boolean isLeftGroup() {
+        return false;
+    }
+
     public void setIconAndLabelFor(View iconView, TextView labelView) {
         if (mIcon != null) {
             mIcon.loadDrawableAsync(iconView.getContext(),