@ActivityView.java
public ActivityView(Contextcontext, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
mActivity = (Activity)context;
break;
}
context = ((ContextWrapper)context).getBaseContext();
}
if (mActivity == null) {
throw new IllegalStateException("The ActivityView's Context is notan Activity.");
}
try {
mActivityContainer = new ActivityContainerWrapper(
ActivityManagerNative.getDefault().createActivityContainer(
mActivity.getActivityToken(), new ActivityContainerCallback(this)));
} catch (RemoteException e) {
throw newRuntimeException("ActivityView: Unable to create ActivityContainer. "
+ e);
}
mTextureView = new TextureView(context);
mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
addView(mTextureView);//putthis view show on System’s device display
WindowManager wm =(WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
mMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(mMetrics);
mLastVisibility = getVisibility();
if (DEBUG) Log.v(TAG, "ctor()");
}
@ActivityManagerNative.java
public IActivityContainer createActivityContainer(IBinderparentActivityToken,
IActivityContainerCallback callback) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(parentActivityToken);
data.writeStrongBinder(callback == null ? null : callback.asBinder());
mRemote.transact(CREATE_ACTIVITY_CONTAINER_TRANSACTION,data, reply, 0);
reply.readException();
final int result = reply.readInt();
final IActivityContainer res;
if (result == 1) {
res = IActivityContainer.Stub.asInterface(reply.readStrongBinder());
} else {
res = null;
}
data.recycle();
reply.recycle();
return res;
}
public abstract class ActivityManagerNative extends Binderimplements IActivityManager
{
case CREATE_ACTIVITY_CONTAINER_TRANSACTION:{
data.enforceInterface(IActivityManager.descriptor);
IBinder parentActivityToken = data.readStrongBinder();
IActivityContainerCallback callback =
IActivityContainerCallback.Stub.asInterface(data.readStrongBinder());
IActivityContainer activityContainer =
createActivityContainer(parentActivityToken,callback);
reply.writeNoException();
if (activityContainer != null) {
reply.writeInt(1);
reply.writeStrongBinder(activityContainer.asBinder());
} else {
reply.writeInt(0);
}
return true;
}
@ActivityManagerService.java
@Override
public IActivityContainer createActivityContainer(IBinderparentActivityToken,
IActivityContainerCallback callback) throws RemoteException {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"createActivityContainer()");
synchronized (this) {
if (parentActivityToken == null) {
throw newIllegalArgumentException("parent token must not be null");
}
ActivityRecord r = ActivityRecord.forToken(parentActivityToken);
if (r == null) {
return null;
}
if (callback == null) {
throw newIllegalArgumentException("callback must not be null");
}
return mStackSupervisor.createActivityContainer(r,callback);
}
}
note: after the ActivityView is shown , the funtion of onSurfaceTextureAvailable would be called , then it would try to set up the VirtualDisplayDevice
@ActivityView.java
public void onSurfaceTextureAvailable(SurfaceTexturesurfaceTexture, int width,
int height) {
mWidth = width;
mHeight = height;
attachToSurfaceWhenReady();
}
private void attachToSurfaceWhenReady(){
final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
if (surfaceTexture == null || mSurface != null) {
// Either not ready to attach, or already attached.
return;
}
mSurface = new Surface(surfaceTexture);
try {
mActivityContainer.setSurface(mSurface, mWidth, mHeight,mMetrics.densityDpi);
//mActivityContainer --binderto VirtualActivityContainer
} catch (RemoteException e) {
mSurface.release();
mSurface = null;
throw new RuntimeException("ActivityView: Unable to createActivityContainer. " + e);
}
}
// class ActivityContainerextends android.app.IActivityContainer.Stub
// class VirtualActivityContainerextends ActivityContainer
public void VirtualActivityContainer::setSurface(Surface surface, int width, intheight, int density) {
super.setSurface(surface, width, height, density);
synchronized (mService) {
final long origId =Binder.clearCallingIdentity();
try {
setSurfaceLocked(surface,width, height, density);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
// class ActivityContainerextends android.app.IActivityContainer.Stub
// class VirtualActivityContainerextends ActivityContainer
private void VirtualActivityContainer::setSurfaceLocked(Surface surface, int width, int height, intdensity) {
if (mContainerState == CONTAINER_STATE_FINISHING) {
return;
}
VirtualActivityDisplay virtualActivityDisplay =
(VirtualActivityDisplay)mActivityDisplay;
if (virtualActivityDisplay == null) {
virtualActivityDisplay =
new VirtualActivityDisplay(width,height, density);
mActivityDisplay =virtualActivityDisplay;
mActivityDisplays.put(virtualActivityDisplay.mDisplayId,virtualActivityDisplay);
attachToDisplayLocked(virtualActivityDisplay);
}
if (mSurface != null) {
mSurface.release();
}
mSurface = surface;
if (surface != null) {
mStack.resumeTopActivityLocked(null);
} else {
mContainerState =CONTAINER_STATE_NO_SURFACE;
((VirtualActivityDisplay)mActivityDisplay).setSurface(null);
if (mStack.mPausingActivity ==null && mStack.mResumedActivity != null) {
mStack.startPausingLocked(false, true, false, false);
}
}
setSurfaceIfReadyLocked();
}
@ActivityStackSupervisor.java
classVirtualActivityDisplay extends ActivityDisplay {
VirtualDisplay mVirtualDisplay;
VirtualActivityDisplay(int width, int height, int density) {
DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, null,
VIRTUAL_DISPLAY_BASE_NAME,width, height, density, null,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, null, null);
init(mVirtualDisplay.getDisplay());
mWindowManager.handleDisplayAdded(mDisplayId);
}
@DisplayManager.java
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
return createVirtualDisplay(null,
name, width, height,densityDpi, surface, flags, callback, handler);
}
//thesurface parameter would be set by call setSurface(Surfacesurface, int width, int height,int density);
/** @hide */
public VirtualDisplay createVirtualDisplay(@NullableMediaProjection projection,
@NonNull String name, int width, int height, int densityDpi, @NullableSurface surface,
int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handlerhandler) {
return mGlobal.createVirtualDisplay(mContext, projection,
name, width, height,densityDpi, surface, flags, callback, handler);
}
@DisplayManagerGlobal.java
public VirtualDisplay createVirtualDisplay(Context context,MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
VirtualDisplay.Callback callback, Handler handler) {
VirtualDisplayCallback callbackWrapper = newVirtualDisplayCallback(callback, handler);
IMediaProjection projectionToken = projection != null ?projection.getProjection() : null;
int displayId;
try {//private final IDisplayManager mDm;//DisplayManagerService.java
displayId = mDm.createVirtualDisplay(callbackWrapper,projectionToken,
context.getPackageName(),name, width, height, densityDpi, surface,flags);
} catch (RemoteException ex) {
Log.e(TAG, "Could not create virtual display: " + name, ex);
return null;
}
Display display = getRealDisplay(displayId);
return new VirtualDisplay(this,display, callbackWrapper,surface);
}
@DisplayManagerService.java
public int createVirtualDisplay(IVirtualDisplayCallbackcallback,
IMediaProjection projection,String packageName, String name,
int width, int height, intdensityDpi, Surface surface, int flags)
{
return createVirtualDisplayInternal(callback,projection, callingUid,
packageName, name,width, height, densityDpi, surface, flags);
}
private int createVirtualDisplayInternal(IVirtualDisplayCallbackcallback,
IMediaProjection projection, int callingUid, String packageName,
String name, int width, int height, int densityDpi, Surface surface, int flags)
{
DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
callback, projection,callingUid, packageName,
name, width, height,densityDpi, surface, flags);
if (device == null) {
return -1;
}
handleDisplayDeviceAddedLocked(device);
LogicalDisplay display =findLogicalDisplayForDeviceLocked(device);
if (display != null) {
returndisplay.getDisplayIdLocked();
}
}
private void registerVirtualDisplayAdapterLocked(){
mVirtualDisplayAdapter = new VirtualDisplayAdapter(
mSyncRoot, mContext, mHandler,mDisplayAdapterListener);
registerDisplayAdapterLocked(mVirtualDisplayAdapter);
}
@VirtualDisplayAdapter.java
public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallbackcallback,
IMediaProjection projection, int ownerUid, String ownerPackageName,
String name, int width, int height, int densityDpi, Surface surface, int flags) {
boolean secure = (flags &DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
IBinder appToken = callback.asBinder();
IBinder displayToken = SurfaceControl.createDisplay(name,secure);
VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken,appToken,
ownerUid, ownerPackageName,name, width, height, densityDpi, surface, flags,
new Callback(callback,mHandler));
mVirtualDisplayDevices.put(appToken, device);
try {
if (projection != null) {
projection.registerCallback(newMediaProjectionCallback(appToken));
}
appToken.linkToDeath(device, 0);
} catch (RemoteException ex) {
mVirtualDisplayDevices.remove(appToken);
device.destroyLocked();
return null;
}
// Return the display device without actually sending the eventindicating
// that it was added. The callerwill handle it.
return device;
}
public VirtualDisplayDevice(IBinderdisplayToken, IBinder appToken,
int ownerUid, StringownerPackageName,
String name, int width, intheight, int densityDpi, Surface surface, intflags,
Callback callback) {
super(VirtualDisplayAdapter.this, displayToken);
mAppToken = appToken;
mOwnerUid = ownerUid;
mOwnerPackageName = ownerPackageName;
mName = name;
mWidth = width;
mHeight = height;
mDensityDpi = densityDpi;
mSurface= surface;
mFlags = flags;
mCallback = callback;
mDisplayState = Display.STATE_UNKNOWN;
mPendingChanges |= PENDING_SURFACE_CHANGE;
}
Please be noted that the surface marked by red, which would be used by the SurfaceFlinger to composition.
and after create the TextureView, it would be added by call addView(); which would make this view to be show on the device's display.