Merge changes from topic 'virtual-display-api' into oc-dev

* changes:
  Add command line option to set compatibility display properties
  Make VR mode virtual display properties customizable
diff --git a/cmds/vr/src/com/android/commands/vr/Vr.java b/cmds/vr/src/com/android/commands/vr/Vr.java
index 3fb40fb..bf97bba 100644
--- a/cmds/vr/src/com/android/commands/vr/Vr.java
+++ b/cmds/vr/src/com/android/commands/vr/Vr.java
@@ -16,6 +16,7 @@
 
 package com.android.commands.vr;
 
+import android.app.CompatibilityDisplayProperties;
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -36,7 +37,10 @@
       (new Vr()).run(args);
     }
 
-    private static final String COMMAND_SET_PERSISTENT_VR_MODE_ENABLED = "set-persistent-vr-mode-enabled";
+    private static final String COMMAND_SET_PERSISTENT_VR_MODE_ENABLED =
+        "set-persistent-vr-mode-enabled";
+    private static final String COMMAND_SET_COMPATIBILITY_DISPLAY_PROPERTIES =
+        "set-display-props";
 
     private IVrManager mVrService;
 
@@ -44,7 +48,8 @@
     public void onShowUsage(PrintStream out) {
         out.println(
                 "usage: vr [subcommand]\n" +
-                "usage: vr set-persistent-vr-mode-enabled [true|false]\n"
+                "usage: vr set-persistent-vr-mode-enabled [true|false]\n" +
+                "usage: vr set-display-props [width] [height] [dpi]\n"
                 );
     }
 
@@ -58,6 +63,9 @@
 
         String command = nextArgRequired();
         switch (command) {
+            case COMMAND_SET_COMPATIBILITY_DISPLAY_PROPERTIES:
+                runSetCompatibilityDisplayProperties();
+                break;
             case COMMAND_SET_PERSISTENT_VR_MODE_ENABLED:
                 runSetPersistentVrModeEnabled();
                 break;
@@ -66,6 +74,26 @@
         }
     }
 
+    private void runSetCompatibilityDisplayProperties() throws RemoteException {
+        String widthStr = nextArgRequired();
+        int width = Integer.parseInt(widthStr);
+
+        String heightStr = nextArgRequired();
+        int height = Integer.parseInt(heightStr);
+
+        String dpiStr = nextArgRequired();
+        int dpi = Integer.parseInt(dpiStr);
+
+        CompatibilityDisplayProperties compatDisplayProperties =
+                new CompatibilityDisplayProperties(width, height, dpi);
+
+        try {
+            mVrService.setCompatibilityDisplayProperties(compatDisplayProperties);
+        } catch (RemoteException re) {
+            System.err.println("Error: Can't set persistent mode " + re);
+        }
+    }
+
     private void runSetPersistentVrModeEnabled() throws RemoteException {
         String enableStr = nextArg();
         boolean enabled = Boolean.parseBoolean(enableStr);
diff --git a/core/java/android/app/CompatibilityDisplayProperties.aidl b/core/java/android/app/CompatibilityDisplayProperties.aidl
new file mode 100644
index 0000000..626a63e
--- /dev/null
+++ b/core/java/android/app/CompatibilityDisplayProperties.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.app;
+
+/** @hide */
+parcelable CompatibilityDisplayProperties;
diff --git a/core/java/android/app/CompatibilityDisplayProperties.java b/core/java/android/app/CompatibilityDisplayProperties.java
new file mode 100644
index 0000000..9a9bc2c
--- /dev/null
+++ b/core/java/android/app/CompatibilityDisplayProperties.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.app;
+
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.PrintWriter;
+
+/**
+ * Display properties to be used by VR mode when creating a virtual display.
+ *
+ * @hide
+ */
+public class CompatibilityDisplayProperties implements Parcelable {
+
+   /**
+    * The actual width, height and dpi.
+    */
+    private final int mWidth;
+    private final int mHeight;
+    private final int mDpi;
+
+    public CompatibilityDisplayProperties(int width, int height, int dpi) {
+        mWidth = width;
+        mHeight = height;
+        mDpi = dpi;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = getWidth();
+        result = 31 * result + getHeight();
+        result = 31 * result + getDpi();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "CompatibilityDisplayProperties{" +
+                "mWidth=" + mWidth +
+                ", mHeight=" + mHeight +
+                ", mDpi=" + mDpi +
+                "}";
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        CompatibilityDisplayProperties that = (CompatibilityDisplayProperties) o;
+
+        if (getWidth() != that.getWidth()) return false;
+        if (getHeight() != that.getHeight()) return false;
+        return getDpi() == that.getDpi();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mWidth);
+        dest.writeInt(mHeight);
+        dest.writeInt(mDpi);
+    }
+
+    public static final Parcelable.Creator<CompatibilityDisplayProperties> CREATOR
+            = new Parcelable.Creator<CompatibilityDisplayProperties>() {
+        @Override
+        public CompatibilityDisplayProperties createFromParcel(Parcel source) {
+            return new CompatibilityDisplayProperties(source);
+        }
+
+        @Override
+        public CompatibilityDisplayProperties[] newArray(int size) {
+            return new CompatibilityDisplayProperties[size];
+        }
+    };
+
+    private CompatibilityDisplayProperties(Parcel source) {
+        mWidth = source.readInt();
+        mHeight = source.readInt();
+        mDpi = source.readInt();
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "CompatibilityDisplayProperties:");
+        pw.println(prefix + "  width=" + mWidth);
+        pw.println(prefix + "  height=" + mHeight);
+        pw.println(prefix + "  dpi=" + mDpi);
+    }
+
+    public int getWidth() {
+        return mWidth;
+    }
+
+    public int getHeight() {
+        return mHeight;
+    }
+
+    public int getDpi() {
+        return mDpi;
+    }
+}
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 4dd578e..878c8c3 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -45,6 +45,26 @@
     }
 
     /**
+     * Sets the resolution and DPI of the compatibility virtual display used to display 2D
+     * applications in VR mode.
+     *
+     * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
+     *
+     * @param {@link android.app.CompatibilityDisplayProperties} properties to be set to the
+     * virtual display for 2D applications in VR mode.
+     *
+     * {@hide}
+     */
+    public void setCompatibilityDisplayProperties(
+            CompatibilityDisplayProperties compatDisplayProp) {
+        try {
+            mService.setCompatibilityDisplayProperties(compatDisplayProp);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Initiate connection for system controller data.
      *
      * @param fd Controller data file descriptor.
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 6eea07d..8b2d0c6 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -16,6 +16,7 @@
 
 package android.service.vr;
 
+import android.app.CompatibilityDisplayProperties;
 import android.service.vr.IVrStateCallbacks;
 import android.service.vr.IPersistentVrStateCallbacks;
 
@@ -67,6 +68,18 @@
     void setPersistentVrModeEnabled(in boolean enabled);
 
     /**
+     * Sets the resolution and DPI of the compatibility virtual display used to display
+     * 2D applications in VR mode.
+     *
+     * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
+     *
+     * @param compatDisplayProperties Compatibitlity display properties to be set for
+     * the VR virtual display
+     */
+    void setCompatibilityDisplayProperties(
+            in CompatibilityDisplayProperties compatDisplayProperties);
+
+    /**
      * Return current virtual display id.
      *
      * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
index c6e52cd..d7cdf08 100644
--- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java
+++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
@@ -3,6 +3,7 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import android.app.ActivityManagerInternal;
+import android.app.CompatibilityDisplayProperties;
 import android.app.Service;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -35,9 +36,9 @@
     private final static boolean DEBUG = false;
 
     // TODO: Go over these values and figure out what is best
-    private final static int HEIGHT = 1800;
-    private final static int WIDTH = 1400;
-    private final static int DPI = 320;
+    private int mVirtualDisplayHeight;
+    private int mVirtualDisplayWidth;
+    private int mVirtualDisplayDpi;
     private final static int STOP_VIRTUAL_DISPLAY_DELAY_MILLIS = 2000;
 
     private final static String DEBUG_ACTION_SET_MODE =
@@ -49,6 +50,28 @@
     private final static String DEBUG_EXTRA_SURFACE =
             "com.android.server.vr.CompatibilityDisplay.EXTRA_SURFACE";
 
+    /**
+     * The default width of the VR virtual display
+     */
+    public static final int DEFAULT_VR_DISPLAY_WIDTH = 1400;
+
+    /**
+     * The default height of the VR virtual display
+     */
+    public static final int DEFAULT_VR_DISPLAY_HEIGHT = 1800;
+
+    /**
+     * The default height of the VR virtual dpi.
+     */
+    public static final int DEFAULT_VR_DISPLAY_DPI = 320;
+
+    /**
+     * The minimum height, width and dpi of VR virtual display.
+     */
+    public static final int MIN_VR_DISPLAY_WIDTH = 1;
+    public static final int MIN_VR_DISPLAY_HEIGHT = 1;
+    public static final int MIN_VR_DISPLAY_DPI = 1;
+
     private final ActivityManagerInternal mActivityManagerInternal;
     private final DisplayManager mDisplayManager;
     private final IVrManager mVrManager;
@@ -81,6 +104,9 @@
         mDisplayManager = displayManager;
         mActivityManagerInternal = activityManagerInternal;
         mVrManager = vrManager;
+        mVirtualDisplayWidth = DEFAULT_VR_DISPLAY_WIDTH;
+        mVirtualDisplayHeight = DEFAULT_VR_DISPLAY_HEIGHT;
+        mVirtualDisplayDpi = DEFAULT_VR_DISPLAY_DPI;
     }
 
     /**
@@ -164,6 +190,47 @@
     }
 
     /**
+     * Sets the resolution and DPI of the compatibility virtual display used to display
+     * 2D applications in VR mode.
+     *
+     * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
+     *
+     * @param compatDisplayProperties Properties of the virtual display for 2D applications
+     * in VR mode.
+     */
+    public void setVirtualDisplayProperties(CompatibilityDisplayProperties compatDisplayProperties) {
+        synchronized(mVdLock) {
+            if (DEBUG) {
+                Log.i(TAG, "VD setVirtualDisplayProperties: res = " +
+                        compatDisplayProperties.getWidth() + "X" + compatDisplayProperties.getHeight() +
+                        ", dpi = " + compatDisplayProperties.getDpi());
+            }
+
+            if (compatDisplayProperties.getWidth() < MIN_VR_DISPLAY_WIDTH ||
+                compatDisplayProperties.getHeight() < MIN_VR_DISPLAY_HEIGHT ||
+                compatDisplayProperties.getDpi() < MIN_VR_DISPLAY_DPI) {
+                throw new IllegalArgumentException (
+                        "Illegal argument: height, width, dpi cannot be negative. res = " +
+                        compatDisplayProperties.getWidth() + "X" + compatDisplayProperties.getHeight() +
+                        ", dpi = " + compatDisplayProperties.getDpi());
+            }
+
+            mVirtualDisplayWidth = compatDisplayProperties.getWidth();
+            mVirtualDisplayHeight = compatDisplayProperties.getHeight();
+            mVirtualDisplayDpi = compatDisplayProperties.getDpi();
+
+            if (mVirtualDisplay != null) {
+                mVirtualDisplay.resize(mVirtualDisplayWidth, mVirtualDisplayHeight,
+                    mVirtualDisplayDpi);
+                ImageReader oldImageReader = mImageReader;
+                mImageReader = null;
+                startImageReader();
+                oldImageReader.close();
+            }
+        }
+    }
+
+    /**
      * Returns the virtual display ID if one currently exists, otherwise returns
      * {@link INVALID_DISPLAY_ID}.
      *
@@ -174,7 +241,7 @@
             if (mVirtualDisplay != null) {
                 int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
                 if (DEBUG) {
-                    Log.e(TAG, "VD id: " + virtualDisplayId);
+                    Log.i(TAG, "VD id: " + virtualDisplayId);
                 }
                 return virtualDisplayId;
             }
@@ -201,8 +268,9 @@
                 return;
             }
 
-            mVirtualDisplay = mDisplayManager.createVirtualDisplay("VR 2D Display", WIDTH, HEIGHT,
-                    DPI, null /* Surface */, 0 /* flags */);
+            mVirtualDisplay = mDisplayManager.createVirtualDisplay("VR 2D Display",
+                    mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
+                    null /* Surface */, 0 /* flags */);
 
             if (mVirtualDisplay != null) {
                 mActivityManagerInternal.setVrCompatibilityDisplayId(
@@ -216,9 +284,7 @@
             }
         }
 
-        if (DEBUG) {
-            Log.d(TAG, "VD created: " + mVirtualDisplay);
-        }
+        Log.i(TAG, "VD created: " + mVirtualDisplay);
     }
 
     /**
@@ -281,8 +347,10 @@
      */
     private void startImageReader() {
         if (mImageReader == null) {
-            mImageReader = ImageReader.newInstance(WIDTH, HEIGHT, PixelFormat.RGBA_8888,
-                2 /* maxImages */);
+            mImageReader = ImageReader.newInstance(mVirtualDisplayWidth, mVirtualDisplayHeight,
+                PixelFormat.RGBA_8888, 2 /* maxImages */);
+            Log.i(TAG, "VD startImageReader: res = " + mVirtualDisplayWidth + "X" +
+                    mVirtualDisplayHeight + ", dpi = " + mVirtualDisplayDpi);
         }
         synchronized (mVdLock) {
             setSurfaceLocked(mImageReader.getSurface());
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 358861d..63c6195 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -16,6 +16,7 @@
 package com.android.server.vr;
 
 import android.annotation.NonNull;
+import android.app.CompatibilityDisplayProperties;
 import android.content.ComponentName;
 import android.service.vr.IPersistentVrStateCallbacks;
 
@@ -82,6 +83,18 @@
     public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
 
     /**
+     * Sets the resolution and DPI of the compatibility virtual display used to display
+     * 2D applications in VR mode.
+     *
+     * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
+     *
+     * @param compatDisplayProp Properties of the virtual display for 2D applications
+     * in VR mode.
+     */
+    public abstract void setCompatibilityDisplayProperties(
+            CompatibilityDisplayProperties compatDisplayProp);
+
+    /**
      * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
      * remain in VR mode even if the foreground does not specify Vr mode being enabled. Mainly used
      * by VR viewers to indicate that a device is placed in a VR viewer.
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index cc08918..39a1573 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
+import android.app.CompatibilityDisplayProperties;
 import android.app.NotificationManager;
 import android.annotation.NonNull;
 import android.content.ComponentName;
@@ -427,6 +428,13 @@
         }
 
         @Override
+        public void setCompatibilityDisplayProperties(
+                CompatibilityDisplayProperties compatDisplayProp) {
+            enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS);
+            VrManagerService.this.setCompatibilityDisplayProperties(compatDisplayProp);
+        }
+
+        @Override
         public int getCompatibilityDisplayId() {
             return VrManagerService.this.getCompatibilityDisplayId();
         }
@@ -541,6 +549,12 @@
         }
 
         @Override
+        public void setCompatibilityDisplayProperties(
+            CompatibilityDisplayProperties compatDisplayProp) {
+            VrManagerService.this.setCompatibilityDisplayProperties(compatDisplayProp);
+        }
+
+        @Override
         public int getCompatibilityDisplayId() {
             return VrManagerService.this.getCompatibilityDisplayId();
         }
@@ -1106,6 +1120,15 @@
         }
     }
 
+    public void setCompatibilityDisplayProperties(
+        CompatibilityDisplayProperties compatDisplayProp) {
+        if (mCompatibilityDisplay != null) {
+            mCompatibilityDisplay.setVirtualDisplayProperties(compatDisplayProp);
+            return;
+        }
+        Slog.w(TAG, "CompatibilityDisplay is null!");
+    }
+
     private int getCompatibilityDisplayId() {
         if (mCompatibilityDisplay != null) {
             return mCompatibilityDisplay.getVirtualDisplayId();