diff options
author | Craig Mautner <cmautner@google.com> | 2013-12-20 09:06:56 -0800 |
---|---|---|
committer | Craig Mautner <cmautner@google.com> | 2014-01-10 10:54:55 -0800 |
commit | 4504de5d5a8e1c7dfb306b16282f348856c24764 (patch) | |
tree | 37a2024993d2d4baf9db3e19878f5c32fbd92236 | |
parent | 9c9975ac3dc63423751c4783162d4ade11d156c1 (diff) | |
download | frameworks_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
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"); |