summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCraig Mautner <cmautner@google.com>2013-12-20 09:06:56 -0800
committerCraig Mautner <cmautner@google.com>2014-01-10 10:54:55 -0800
commit4504de5d5a8e1c7dfb306b16282f348856c24764 (patch)
tree37a2024993d2d4baf9db3e19878f5c32fbd92236
parent9c9975ac3dc63423751c4783162d4ade11d156c1 (diff)
downloadframeworks_base-4504de5d5a8e1c7dfb306b16282f348856c24764.zip
frameworks_base-4504de5d5a8e1c7dfb306b16282f348856c24764.tar.gz
frameworks_base-4504de5d5a8e1c7dfb306b16282f348856c24764.tar.bz2
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
-rw-r--r--api/current.txt8
-rw-r--r--core/java/android/app/ActivityView.java163
-rw-r--r--core/java/android/app/IActivityContainer.aidl3
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java91
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java36
7 files changed, 285 insertions, 23 deletions
diff --git a/api/current.txt b/api/current.txt
index 6244e71..3848242 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
new file mode 100644
index 0000000..fef4597
--- /dev/null
+++ b/core/java/android/app/ActivityView.java
@@ -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) {
+
+ }
+
+ }
+}
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index 2d8d18f..b03a459 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -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();
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java b/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
index 6bf4beb..968976b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
@@ -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."
};
/**
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f5acbfd..ed11470 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -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);
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 073e24a..12ef65a 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -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(
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ea56363..f679846 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -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");