[MediaProjection] Store WindowContext in VirtualDisplay
Follow on from ag/15684817, where the WindowContext is cached in MediaProjection. To allow multiple VirtualDisplays to be created from the same MediaProjection, instead create a new WindowContext for each one, and associate with that VirtualDisplay. As before, the WindowContext must be stored in a field to prevent it from being garbage collected. Bug: 197579637 Bug: 198415847 Test: manual Change-Id: If3f84b3778104bf12617d224876700f8ee3b2b45
This commit is contained in:
@@ -864,7 +864,8 @@ public final class DisplayManager {
|
||||
if (surface != null) {
|
||||
builder.setSurface(surface);
|
||||
}
|
||||
return createVirtualDisplay(null /* projection */, builder.build(), callback, handler);
|
||||
return createVirtualDisplay(null /* projection */, builder.build(), callback, handler,
|
||||
null /* windowContext */);
|
||||
}
|
||||
|
||||
// TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService)
|
||||
@@ -882,15 +883,17 @@ public final class DisplayManager {
|
||||
if (surface != null) {
|
||||
builder.setSurface(surface);
|
||||
}
|
||||
return createVirtualDisplay(projection, builder.build(), callback, handler);
|
||||
return createVirtualDisplay(projection, builder.build(), callback, handler,
|
||||
null /* windowContext */);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
|
||||
@NonNull VirtualDisplayConfig virtualDisplayConfig,
|
||||
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
|
||||
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
|
||||
@Nullable Context windowContext) {
|
||||
return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
|
||||
handler);
|
||||
handler, windowContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -583,7 +583,7 @@ public final class DisplayManagerGlobal {
|
||||
|
||||
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
|
||||
@NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
|
||||
Handler handler) {
|
||||
Handler handler, @Nullable Context windowContext) {
|
||||
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
|
||||
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
|
||||
int displayId;
|
||||
@@ -609,7 +609,7 @@ public final class DisplayManagerGlobal {
|
||||
return null;
|
||||
}
|
||||
return new VirtualDisplay(this, display, callbackWrapper,
|
||||
virtualDisplayConfig.getSurface());
|
||||
virtualDisplayConfig.getSurface(), windowContext);
|
||||
}
|
||||
|
||||
public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package android.hardware.display;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
|
||||
@@ -36,13 +38,19 @@ public final class VirtualDisplay {
|
||||
private final Display mDisplay;
|
||||
private IVirtualDisplayCallback mToken;
|
||||
private Surface mSurface;
|
||||
/**
|
||||
* Store the WindowContext in a field. If it is a local variable, and it is garbage collected
|
||||
* during a MediaProjection session, the WindowContainer listener no longer exists.
|
||||
*/
|
||||
@Nullable private final Context mWindowContext;
|
||||
|
||||
VirtualDisplay(DisplayManagerGlobal global, Display display,
|
||||
IVirtualDisplayCallback token, Surface surface) {
|
||||
IVirtualDisplayCallback token, Surface surface, Context windowContext) {
|
||||
mGlobal = global;
|
||||
mDisplay = display;
|
||||
mToken = token;
|
||||
mSurface = surface;
|
||||
mWindowContext = windowContext;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.hardware.display.VirtualDisplayConfig;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
@@ -50,13 +51,6 @@ public final class MediaProjection {
|
||||
private final Context mContext;
|
||||
private final Map<Callback, CallbackRecord> mCallbacks;
|
||||
|
||||
/**
|
||||
* Store the WindowContext in a field. If it is a local variable, and it is garbage collected
|
||||
* during a MediaProjection session, the WindowContainer listener no longer exists.
|
||||
*/
|
||||
@Nullable
|
||||
private Context mWindowContext;
|
||||
|
||||
/** @hide */
|
||||
public MediaProjection(Context context, IMediaProjection impl) {
|
||||
mCallbacks = new ArrayMap<Callback, CallbackRecord>();
|
||||
@@ -107,19 +101,22 @@ public final class MediaProjection {
|
||||
public VirtualDisplay createVirtualDisplay(@NonNull String name,
|
||||
int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
|
||||
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
|
||||
DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
|
||||
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
|
||||
| DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
|
||||
if (isSecure) {
|
||||
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
|
||||
}
|
||||
Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
|
||||
TYPE_APPLICATION, null /* options */);
|
||||
final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
|
||||
height, dpi);
|
||||
height, dpi, windowContext.getWindowContextToken());
|
||||
builder.setFlags(flags);
|
||||
if (surface != null) {
|
||||
builder.setSurface(surface);
|
||||
}
|
||||
return dm.createVirtualDisplay(this, builder.build(), callback, handler);
|
||||
VirtualDisplay virtualDisplay = createVirtualDisplay(builder.build(), callback, handler,
|
||||
windowContext);
|
||||
return virtualDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,13 +145,17 @@ public final class MediaProjection {
|
||||
public VirtualDisplay createVirtualDisplay(@NonNull String name,
|
||||
int width, int height, int dpi, int flags, @Nullable Surface surface,
|
||||
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
|
||||
Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
|
||||
TYPE_APPLICATION, null /* options */);
|
||||
final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
|
||||
height, dpi);
|
||||
height, dpi, windowContext.getWindowContextToken());
|
||||
builder.setFlags(flags);
|
||||
if (surface != null) {
|
||||
builder.setSurface(surface);
|
||||
}
|
||||
return createVirtualDisplay(builder.build(), callback, handler);
|
||||
VirtualDisplay virtualDisplay = createVirtualDisplay(builder.build(), callback, handler,
|
||||
windowContext);
|
||||
return virtualDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,12 +169,10 @@ public final class MediaProjection {
|
||||
* @return a config representing a VirtualDisplay
|
||||
*/
|
||||
private VirtualDisplayConfig.Builder buildMirroredVirtualDisplay(@NonNull String name,
|
||||
int width, int height, int dpi) {
|
||||
mWindowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
|
||||
TYPE_APPLICATION, null /* options */);
|
||||
int width, int height, int dpi, IBinder windowContextToken) {
|
||||
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
|
||||
height, dpi);
|
||||
builder.setWindowTokenClientToMirror(mWindowContext.getWindowContextToken());
|
||||
builder.setWindowTokenClientToMirror(windowContextToken);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -183,20 +182,22 @@ public final class MediaProjection {
|
||||
*
|
||||
* @param virtualDisplayConfig The arguments for the virtual display configuration. See
|
||||
* {@link VirtualDisplayConfig} for using it.
|
||||
* @param callback Callback to call when the virtual display's state
|
||||
* changes, or null if none.
|
||||
* @param handler The {@link android.os.Handler} on which the callback should be
|
||||
* invoked, or null if the callback should be invoked on the calling
|
||||
* thread's main {@link android.os.Looper}.
|
||||
* @param callback Callback to call when the virtual display's state changes, or null if none.
|
||||
* @param handler The {@link android.os.Handler} on which the callback should be invoked, or
|
||||
* null if the callback should be invoked on the calling thread's main
|
||||
* {@link android.os.Looper}.
|
||||
* @param windowContext the WindowContext associated with the caller.
|
||||
*
|
||||
* @see android.hardware.display.VirtualDisplay
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public VirtualDisplay createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
|
||||
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
|
||||
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
|
||||
Context windowContext) {
|
||||
DisplayManager dm = mContext.getSystemService(DisplayManager.class);
|
||||
return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler);
|
||||
return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler,
|
||||
windowContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -302,7 +302,8 @@ class Vr2dDisplay {
|
||||
builder.setUniqueId(UNIQUE_DISPLAY_ID);
|
||||
builder.setFlags(flags);
|
||||
mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
|
||||
builder.build(), null /* callback */, null /* handler */);
|
||||
builder.build(), null /* callback */, null /* handler */,
|
||||
null /* windowContext */);
|
||||
|
||||
if (mVirtualDisplay != null) {
|
||||
updateDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
|
||||
|
||||
Reference in New Issue
Block a user