Implement ActivityView.
With an existing ActivityContainer a caller can now create an ActivityView which consists of a new VirtualDisplay immediately attached to the ActivityContainer. Change-Id: Id70333dcbef55d524a87df8f8c92d72ca5579364
This commit is contained in:
@ -3080,6 +3080,14 @@ package android.app {
|
||||
method public void update(android.app.ActivityOptions);
|
||||
}
|
||||
|
||||
public class ActivityView extends android.view.ViewGroup {
|
||||
ctor public ActivityView(android.content.Context);
|
||||
ctor public ActivityView(android.content.Context, android.util.AttributeSet);
|
||||
ctor public ActivityView(android.content.Context, android.util.AttributeSet, int);
|
||||
method protected void onLayout(boolean, int, int, int, int);
|
||||
method public void startActivity(android.content.Intent);
|
||||
}
|
||||
|
||||
public class AlarmManager {
|
||||
method public void cancel(android.app.PendingIntent);
|
||||
method public void set(int, long, android.app.PendingIntent);
|
||||
|
163
core/java/android/app/ActivityView.java
Normal file
163
core/java/android/app/ActivityView.java
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Surface;
|
||||
import android.view.TextureView;
|
||||
import android.view.TextureView.SurfaceTextureListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class ActivityView extends ViewGroup {
|
||||
private final TextureView mTextureView;
|
||||
private IActivityContainer mActivityContainer;
|
||||
private Activity mActivity;
|
||||
private boolean mAttached;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
public ActivityView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActivityView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ActivityView(Context context, 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 not an Activity.");
|
||||
}
|
||||
|
||||
mTextureView = new TextureView(context);
|
||||
mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
|
||||
addView(mTextureView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
mTextureView.layout(l, t, r, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
try {
|
||||
final IBinder token = mActivity.getActivityToken();
|
||||
mActivityContainer =
|
||||
ActivityManagerNative.getDefault().createActivityContainer(token, null);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("ActivityView: Unable to create ActivityContainer. "
|
||||
+ e);
|
||||
}
|
||||
|
||||
final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
|
||||
if (surfaceTexture != null) {
|
||||
createActivityView(surfaceTexture);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
if (mActivityContainer != null) {
|
||||
try {
|
||||
mActivityContainer.deleteActivityView();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
mActivityContainer = null;
|
||||
}
|
||||
mAttached = false;
|
||||
}
|
||||
|
||||
public void startActivity(Intent intent) {
|
||||
if (mActivityContainer != null && mAttached) {
|
||||
try {
|
||||
mActivityContainer.startActivity(intent);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("ActivityView: Unable to startActivity. " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Call when both mActivityContainer and mTextureView's SurfaceTexture are not null */
|
||||
private void createActivityView(SurfaceTexture surfaceTexture) {
|
||||
WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getMetrics(metrics);
|
||||
|
||||
try {
|
||||
mActivityContainer.createActivityView(new Surface(surfaceTexture), mWidth, mHeight,
|
||||
metrics.densityDpi);
|
||||
} catch (RemoteException e) {
|
||||
mActivityContainer = null;
|
||||
throw new IllegalStateException(
|
||||
"ActivityView: Unable to create ActivityContainer. " + e);
|
||||
}
|
||||
mAttached = true;
|
||||
}
|
||||
|
||||
private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
|
||||
int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
if (mActivityContainer != null) {
|
||||
createActivityView(surfaceTexture);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
|
||||
int height) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
|
||||
try {
|
||||
mActivityContainer.deleteActivityView();
|
||||
// TODO: Add binderDied to handle this nullification.
|
||||
mActivityContainer = null;
|
||||
} catch (RemoteException r) {
|
||||
}
|
||||
mAttached = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ package android.app;
|
||||
import android.app.IActivityContainerCallback;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.view.Surface;
|
||||
|
||||
/** @hide */
|
||||
interface IActivityContainer {
|
||||
@ -26,4 +27,6 @@ interface IActivityContainer {
|
||||
int getDisplayId();
|
||||
void detachFromDisplay();
|
||||
int startActivity(in Intent intent);
|
||||
void createActivityView(in Surface surface, int width, int height, int density);
|
||||
void deleteActivityView();
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ import android.view.LayoutInflater;
|
||||
public class PhoneLayoutInflater extends LayoutInflater {
|
||||
private static final String[] sClassPrefixList = {
|
||||
"android.widget.",
|
||||
"android.webkit."
|
||||
"android.webkit.",
|
||||
"android.app."
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -59,6 +59,8 @@ import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManager.DisplayListener;
|
||||
import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
@ -79,6 +81,7 @@ import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.Surface;
|
||||
import com.android.internal.app.HeavyWeightSwitcherActivity;
|
||||
import com.android.internal.os.TransferPipe;
|
||||
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
|
||||
@ -88,6 +91,7 @@ import com.android.server.wm.WindowManagerService;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -119,6 +123,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
|
||||
static final int HANDLE_DISPLAY_CHANGED = FIRST_SUPERVISOR_STACK_MSG + 6;
|
||||
static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7;
|
||||
|
||||
private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
|
||||
|
||||
// For debugging to make sure the caller when acquiring/releasing our
|
||||
// wake lock is the system process.
|
||||
@ -212,11 +217,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
|
||||
/** Stack id of the front stack when user switched, indexed by userId. */
|
||||
SparseIntArray mUserStackInFront = new SparseIntArray(2);
|
||||
|
||||
// TODO: Add listener for removal of references.
|
||||
/** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
|
||||
SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
|
||||
SparseArray<WeakReference<ActivityContainer>> mActivityContainers =
|
||||
new SparseArray<WeakReference<ActivityContainer>>();
|
||||
|
||||
/** Mapping from displayId to display current state */
|
||||
SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<ActivityDisplay>();
|
||||
private SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<ActivityDisplay>();
|
||||
|
||||
public ActivityStackSupervisor(ActivityManagerService service) {
|
||||
mService = service;
|
||||
@ -2098,9 +2105,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
|
||||
}
|
||||
|
||||
ActivityStack getStack(int stackId) {
|
||||
ActivityContainer activityContainer = mActivityContainers.get(stackId);
|
||||
if (activityContainer != null) {
|
||||
return activityContainer.mStack;
|
||||
WeakReference<ActivityContainer> weakReference = mActivityContainers.get(stackId);
|
||||
if (weakReference != null) {
|
||||
ActivityContainer activityContainer = weakReference.get();
|
||||
if (activityContainer != null) {
|
||||
return activityContainer.mStack;
|
||||
} else {
|
||||
mActivityContainers.remove(stackId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -2134,7 +2146,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
|
||||
IActivityContainerCallback callback) {
|
||||
ActivityContainer activityContainer = new ActivityContainer(parentActivity, stackId,
|
||||
callback);
|
||||
mActivityContainers.put(stackId, activityContainer);
|
||||
mActivityContainers.put(stackId, new WeakReference<ActivityContainer>(activityContainer));
|
||||
if (parentActivity != null) {
|
||||
parentActivity.mChildContainers.add(activityContainer.mStack);
|
||||
}
|
||||
@ -2728,11 +2740,17 @@ public final class ActivityStackSupervisor implements DisplayListener {
|
||||
}
|
||||
|
||||
public void handleDisplayAddedLocked(int displayId) {
|
||||
boolean newDisplay;
|
||||
synchronized (mService) {
|
||||
ActivityDisplay activityDisplay = new ActivityDisplay(displayId);
|
||||
mActivityDisplays.put(displayId, activityDisplay);
|
||||
newDisplay = mActivityDisplays.get(displayId) == null;
|
||||
if (newDisplay) {
|
||||
ActivityDisplay activityDisplay = new ActivityDisplay(displayId);
|
||||
mActivityDisplays.put(displayId, activityDisplay);
|
||||
}
|
||||
}
|
||||
if (newDisplay) {
|
||||
mWindowManager.onDisplayAdded(displayId);
|
||||
}
|
||||
mWindowManager.onDisplayAdded(displayId);
|
||||
}
|
||||
|
||||
public void handleDisplayRemovedLocked(int displayId) {
|
||||
@ -2960,6 +2978,49 @@ public final class ActivityStackSupervisor implements DisplayListener {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createActivityView(Surface surface, int width, int height, int density) {
|
||||
DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
|
||||
VirtualDisplay virtualDisplay;
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
virtualDisplay = dm.createVirtualDisplay(mService.mContext,
|
||||
VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface,
|
||||
// TODO: Add VIRTUAL_DISPLAY_FLAG_DISABLE_MIRRORING when it is available.
|
||||
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
|
||||
final Display display = virtualDisplay.getDisplay();
|
||||
final int displayId = display.getDisplayId();
|
||||
|
||||
// Do WindowManager operation first so that it is ahead of CREATE_STACK in the H queue.
|
||||
mWindowManager.onDisplayAdded(displayId);
|
||||
|
||||
synchronized (mService) {
|
||||
ActivityDisplay activityDisplay = new ActivityDisplay(display);
|
||||
mActivityDisplays.put(displayId, activityDisplay);
|
||||
attachToDisplayLocked(activityDisplay);
|
||||
activityDisplay.mVirtualDisplay = virtualDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteActivityView() {
|
||||
synchronized (mService) {
|
||||
if (!isAttached()) {
|
||||
return;
|
||||
}
|
||||
VirtualDisplay virtualDisplay = mActivityDisplay.mVirtualDisplay;
|
||||
if (virtualDisplay != null) {
|
||||
virtualDisplay.release();
|
||||
mActivityDisplay.mVirtualDisplay = null;
|
||||
}
|
||||
detachLocked();
|
||||
}
|
||||
}
|
||||
|
||||
ActivityStackSupervisor getOuter() {
|
||||
return ActivityStackSupervisor.this;
|
||||
}
|
||||
@ -2989,9 +3050,17 @@ public final class ActivityStackSupervisor implements DisplayListener {
|
||||
* stacks, bottommost behind. Accessed directly by ActivityManager package classes */
|
||||
final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
|
||||
|
||||
/** If this display is for an ActivityView then the VirtualDisplay created for it is stored
|
||||
* here. */
|
||||
VirtualDisplay mVirtualDisplay;
|
||||
|
||||
ActivityDisplay(int displayId) {
|
||||
mDisplayId = displayId;
|
||||
mDisplay = mDisplayManager.getDisplay(displayId);
|
||||
this(mDisplayManager.getDisplay(displayId));
|
||||
}
|
||||
|
||||
ActivityDisplay(Display display) {
|
||||
mDisplay = display;
|
||||
mDisplayId = display.getDisplayId();
|
||||
mDisplay.getDisplayInfo(mDisplayInfo);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
@ -675,7 +676,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
|
||||
if (surface == null) {
|
||||
throw new IllegalArgumentException("surface must not be null");
|
||||
}
|
||||
if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
|
||||
if (callingUid != Process.SYSTEM_UID &&
|
||||
(flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
|
||||
if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
&& mContext.checkCallingPermission(
|
||||
|
@ -4817,22 +4817,31 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
public void createStack(int stackId, int displayId) {
|
||||
mH.sendMessage(mH.obtainMessage(H.CREATE_STACK, stackId, displayId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new TaskStack and place it next to an existing stack.
|
||||
* @param stackId The unique identifier of the new stack.
|
||||
*/
|
||||
public void createStack(int stackId, int displayId) {
|
||||
synchronized (mWindowMap) {
|
||||
final int numDisplays = mDisplayContents.size();
|
||||
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
|
||||
final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
|
||||
if (displayContent.getDisplayId() == displayId) {
|
||||
TaskStack stack = displayContent.createStack(stackId);
|
||||
mStackIdToStack.put(stackId, stack);
|
||||
performLayoutAndPlaceSurfacesLocked();
|
||||
return;
|
||||
private void createStackLocked(int stackId, int displayId) {
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mWindowMap) {
|
||||
final int numDisplays = mDisplayContents.size();
|
||||
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
|
||||
final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
|
||||
if (displayContent.getDisplayId() == displayId) {
|
||||
TaskStack stack = displayContent.createStack(stackId);
|
||||
mStackIdToStack.put(stackId, stack);
|
||||
performLayoutAndPlaceSurfacesLocked();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7038,6 +7047,8 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
public static final int REMOVE_STARTING_TIMEOUT = 33;
|
||||
|
||||
public static final int CREATE_STACK = 34;
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (DEBUG_WINDOW_TRACE) {
|
||||
@ -7481,6 +7492,11 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
break;
|
||||
case CREATE_STACK:
|
||||
synchronized (mWindowMap) {
|
||||
createStackLocked(msg.arg1, msg.arg2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (DEBUG_WINDOW_TRACE) {
|
||||
Slog.v(TAG, "handleMessage: exit");
|
||||
|
Reference in New Issue
Block a user