diff options
14 files changed, 495 insertions, 223 deletions
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 51cb12a..edf21dd 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -33,17 +33,20 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.TextureView; import android.view.TextureView.SurfaceTextureListener; -import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import dalvik.system.CloseGuard; + +import java.lang.ref.WeakReference; /** @hide */ public class ActivityView extends ViewGroup { - private final String TAG = "ActivityView"; - private final boolean DEBUG = false; + private static final String TAG = "ActivityView"; + private static final boolean DEBUG = false; + DisplayMetrics mMetrics; private final TextureView mTextureView; - private IActivityContainer mActivityContainer; + private ActivityContainerWrapper mActivityContainer; private Activity mActivity; private int mWidth; private int mHeight; @@ -75,68 +78,33 @@ public class ActivityView extends ViewGroup { throw new IllegalStateException("The ActivityView's Context is not an Activity."); } - mTextureView = new TextureView(context); - mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); - addView(mTextureView); - if (DEBUG) Log.v(TAG, "ctor()"); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - mTextureView.layout(0, 0, r - l, b - t); - } - - @Override - protected void onAttachedToWindow() { - if (DEBUG) Log.v(TAG, "onAttachedToWindow()"); - super.onAttachedToWindow(); try { - final IBinder token = mActivity.getActivityToken(); - mActivityContainer = ActivityManagerNative.getDefault().createActivityContainer(token, - new ActivityContainerCallback()); + mActivityContainer = new ActivityContainerWrapper( + ActivityManagerNative.getDefault().createActivityContainer( + mActivity.getActivityToken(), new ActivityContainerCallback(this))); } catch (RemoteException e) { - throw new IllegalStateException("ActivityView: Unable to create ActivityContainer. " + throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e); } - attachToSurfaceWhenReady(); - } + mTextureView = new TextureView(context); + mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); + addView(mTextureView); - @Override - protected void onDetachedFromWindow() { - if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer); - super.onDetachedFromWindow(); - if (mActivityContainer != null) { - detach(); - try { - ActivityManagerNative.getDefault().deleteActivityContainer(mActivityContainer); - } catch (RemoteException e) { - } - mActivityContainer = null; - } + WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE); + mMetrics = new DisplayMetrics(); + wm.getDefaultDisplay().getMetrics(mMetrics); + + if (DEBUG) Log.v(TAG, "ctor()"); } @Override - protected void onWindowVisibilityChanged(int visibility) { - if (DEBUG) Log.v(TAG, "onWindowVisibilityChanged(): visibility=" + visibility); - super.onWindowVisibilityChanged(visibility); - switch (visibility) { - case View.VISIBLE: - attachToSurfaceWhenReady(); - break; - case View.INVISIBLE: - break; - case View.GONE: - break; - } + protected void onLayout(boolean changed, int l, int t, int r, int b) { + mTextureView.layout(0, 0, r - l, b - t); } private boolean injectInputEvent(InputEvent event) { - try { - return mActivityContainer != null && mActivityContainer.injectEvent(event); - } catch (RemoteException e) { - return false; - } + return mActivityContainer != null && mActivityContainer.injectEvent(event); } @Override @@ -154,40 +122,45 @@ public class ActivityView extends ViewGroup { return super.onGenericMotionEvent(event); } + @Override + public void onAttachedToWindow() { + if (DEBUG) Log.v(TAG, "onAttachedToWindow(): mActivityContainer=" + mActivityContainer + + " mSurface=" + mSurface); + } + + @Override + public void onDetachedFromWindow() { + if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer + + " mSurface=" + mSurface); + } + public boolean isAttachedToDisplay() { return mSurface != null; } public void startActivity(Intent intent) { + if (mActivityContainer == null) { + throw new IllegalStateException("Attempt to call startActivity after release"); + } if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); if (mSurface != null) { - try { - mActivityContainer.startActivity(intent); - } catch (RemoteException e) { - throw new IllegalStateException("ActivityView: Unable to startActivity. " + e); - } + mActivityContainer.startActivity(intent); } else { mQueuedIntent = intent; mQueuedPendingIntent = null; } } - private void startActivityIntentSender(IIntentSender iIntentSender) { - try { - mActivityContainer.startActivityIntentSender(iIntentSender); - } catch (RemoteException e) { - throw new IllegalStateException( - "ActivityView: Unable to startActivity from IntentSender. " + e); - } - } - public void startActivity(IntentSender intentSender) { + if (mActivityContainer == null) { + throw new IllegalStateException("Attempt to call startActivity after release"); + } if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); final IIntentSender iIntentSender = intentSender.getTarget(); if (mSurface != null) { - startActivityIntentSender(iIntentSender); + mActivityContainer.startActivityIntentSender(iIntentSender); } else { mQueuedPendingIntent = iIntentSender; mQueuedIntent = null; @@ -195,84 +168,102 @@ public class ActivityView extends ViewGroup { } public void startActivity(PendingIntent pendingIntent) { + if (mActivityContainer == null) { + throw new IllegalStateException("Attempt to call startActivity after release"); + } if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); final IIntentSender iIntentSender = pendingIntent.getTarget(); if (mSurface != null) { - startActivityIntentSender(iIntentSender); + mActivityContainer.startActivityIntentSender(iIntentSender); } else { mQueuedPendingIntent = iIntentSender; mQueuedIntent = null; } } + public void release() { + if (DEBUG) Log.v(TAG, "release() mActivityContainer=" + mActivityContainer + + " mSurface=" + mSurface); + if (mActivityContainer == null) { + Log.e(TAG, "Duplicate call to release"); + return; + } + mActivityContainer.release(); + mActivityContainer = null; + + if (mSurface != null) { + mSurface.release(); + mSurface = null; + } + + mTextureView.setSurfaceTextureListener(null); + } + private void attachToSurfaceWhenReady() { final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); - if (mActivityContainer == null || surfaceTexture == null || mSurface != null) { + if (surfaceTexture == null || mSurface != null) { // Either not ready to attach, or already attached. return; } - WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE); - DisplayMetrics metrics = new DisplayMetrics(); - wm.getDefaultDisplay().getMetrics(metrics); - mSurface = new Surface(surfaceTexture); try { - mActivityContainer.attachToSurface(mSurface, mWidth, mHeight, metrics.densityDpi); + mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi); } catch (RemoteException e) { mSurface.release(); mSurface = null; - throw new IllegalStateException( - "ActivityView: Unable to create ActivityContainer. " + e); + throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e); } if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null || mQueuedPendingIntent != null ? "" : "no") + " queued intent"); if (mQueuedIntent != null) { - startActivity(mQueuedIntent); + mActivityContainer.startActivity(mQueuedIntent); mQueuedIntent = null; } else if (mQueuedPendingIntent != null) { - startActivityIntentSender(mQueuedPendingIntent); + mActivityContainer.startActivityIntentSender(mQueuedPendingIntent); mQueuedPendingIntent = null; } } - private void detach() { - if (DEBUG) Log.d(TAG, "detach: attached=" + isAttachedToDisplay()); - if (mSurface != null) { - try { - mActivityContainer.detachFromDisplay(); - } catch (RemoteException e) { - } - mSurface.release(); - mSurface = null; - } - } - private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { + if (mActivityContainer == null) { + return; + } if (DEBUG) Log.d(TAG, "onSurfaceTextureAvailable: width=" + width + " height=" + height); mWidth = width; mHeight = height; - if (mActivityContainer != null) { - attachToSurfaceWhenReady(); - } + attachToSurfaceWhenReady(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { + if (mActivityContainer == null) { + return; + } if (DEBUG) Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { + if (mActivityContainer == null) { + return true; + } if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed"); - detach(); + mSurface.release(); + mSurface = null; + try { + mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi); + } catch (RemoteException e) { + throw new RuntimeException( + "ActivityView: Unable to set surface of ActivityContainer. " + e); + } return true; } @@ -283,13 +274,95 @@ public class ActivityView extends ViewGroup { } - private class ActivityContainerCallback extends IActivityContainerCallback.Stub { + private static class ActivityContainerCallback extends IActivityContainerCallback.Stub { + private final WeakReference<ActivityView> mActivityViewWeakReference; + + ActivityContainerCallback(ActivityView activityView) { + mActivityViewWeakReference = new WeakReference<ActivityView>(activityView); + } + @Override public void setVisible(IBinder container, boolean visible) { - if (DEBUG) Log.v(TAG, "setVisible(): container=" + container + " visible=" + visible); - if (visible) { - } else { + if (DEBUG) Log.v(TAG, "setVisible(): container=" + container + " visible=" + visible + + " ActivityView=" + mActivityViewWeakReference.get()); + } + } + + private static class ActivityContainerWrapper { + private final IActivityContainer mIActivityContainer; + private final CloseGuard mGuard = CloseGuard.get(); + + ActivityContainerWrapper(IActivityContainer container) { + mIActivityContainer = container; + mGuard.open("release"); + } + + void attachToDisplay(int displayId) { + try { + mIActivityContainer.attachToDisplay(displayId); + } catch (RemoteException e) { + } + } + + void setSurface(Surface surface, int width, int height, int density) + throws RemoteException { + mIActivityContainer.setSurface(surface, width, height, density); + } + + int startActivity(Intent intent) { + try { + return mIActivityContainer.startActivity(intent); + } catch (RemoteException e) { + throw new RuntimeException("ActivityView: Unable to startActivity. " + e); + } + } + + int startActivityIntentSender(IIntentSender intentSender) { + try { + return mIActivityContainer.startActivityIntentSender(intentSender); + } catch (RemoteException e) { + throw new RuntimeException( + "ActivityView: Unable to startActivity from IntentSender. " + e); + } + } + + int getDisplayId() { + try { + return mIActivityContainer.getDisplayId(); + } catch (RemoteException e) { + return -1; } } + + boolean injectEvent(InputEvent event) { + try { + return mIActivityContainer.injectEvent(event); + } catch (RemoteException e) { + return false; + } + } + + void release() { + if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called"); + try { + mIActivityContainer.release(); + mGuard.close(); + } catch (RemoteException e) { + } + } + + @Override + protected void finalize() throws Throwable { + if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: finalize called"); + try { + if (mGuard != null) { + mGuard.warnIfOpen(); + release(); + } + } finally { + super.finalize(); + } + } + } } diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl index 5b80e06..cc3b10c 100644 --- a/core/java/android/app/IActivityContainer.aidl +++ b/core/java/android/app/IActivityContainer.aidl @@ -26,10 +26,10 @@ import android.view.Surface; /** @hide */ interface IActivityContainer { void attachToDisplay(int displayId); - void attachToSurface(in Surface surface, int width, int height, int density); - void detachFromDisplay(); + void setSurface(in Surface surface, int width, int height, int density); int startActivity(in Intent intent); int startActivityIntentSender(in IIntentSender intentSender); int getDisplayId(); boolean injectEvent(in InputEvent event); + void release(); } diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java index a9b7176..7745bb7 100644 --- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java +++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java @@ -61,6 +61,9 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker { private static final boolean DBG = true; private static final boolean VDBG = true; + // Event sent to the mBtdtHandler when DHCP fails so we can tear down the network. + private static final int EVENT_NETWORK_FAILED = 1; + private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); @@ -328,6 +331,7 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker { } if (!success) { Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError()); + mBtdtHandler.obtainMessage(EVENT_NETWORK_FAILED).sendToTarget(); return; } mLinkProperties = dhcpResults.linkProperties; @@ -420,6 +424,10 @@ public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker { if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties); mBtdt.stopReverseTether(); break; + case EVENT_NETWORK_FAILED: + if (VDBG) Log.d(TAG, "got EVENT_NETWORK_FAILED"); + mBtdt.teardown(); + break; } } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index bac7fac..7d5881c 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3726,7 +3726,8 @@ public final class ViewRootImpl implements ViewParent, if (result == InputMethodManager.DISPATCH_HANDLED) { return FINISH_HANDLED; } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) { - return FINISH_NOT_HANDLED; + // The IME could not handle it, so skip along to the next InputStage + return FORWARD; } else { return DEFER; // callback will be invoked later } diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml index 60b6dc1..cbfa84d 100644 --- a/core/tests/bluetoothtests/AndroidManifest.xml +++ b/core/tests/bluetoothtests/AndroidManifest.xml @@ -31,5 +31,8 @@ <instrumentation android:name="android.bluetooth.BluetoothTestRunner" android:targetPackage="com.android.bluetooth.tests" android:label="Bluetooth Tests" /> + <instrumentation android:name="android.bluetooth.BluetoothInstrumentation" + android:targetPackage="com.android.bluetooth.tests" + android:label="Bluetooth Test Utils" /> </manifest> diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java new file mode 100644 index 0000000..34393f9 --- /dev/null +++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +import android.app.Activity; +import android.app.Instrumentation; +import android.content.Context; +import android.os.Bundle; + +public class BluetoothInstrumentation extends Instrumentation { + + private BluetoothTestUtils mUtils = null; + private BluetoothAdapter mAdapter = null; + private Bundle mArgs = null; + + private BluetoothTestUtils getBluetoothTestUtils() { + if (mUtils == null) { + mUtils = new BluetoothTestUtils(getContext(), + BluetoothInstrumentation.class.getSimpleName()); + } + return mUtils; + } + + private BluetoothAdapter getBluetoothAdapter() { + if (mAdapter == null) { + mAdapter = ((BluetoothManager)getContext().getSystemService( + Context.BLUETOOTH_SERVICE)).getAdapter(); + } + return mAdapter; + } + + @Override + public void onCreate(Bundle arguments) { + super.onCreate(arguments); + mArgs = arguments; + start(); + } + + @Override + public void onStart() { + String command = mArgs.getString("command"); + if ("enable".equals(command)) { + enable(); + } else if ("disable".equals(command)) { + disable(); + } else if ("unpairAll".equals(command)) { + unpairAll(); + } else if ("getName".equals(command)) { + getName(); + } else { + finish(null); + } + } + + public void enable() { + getBluetoothTestUtils().enable(getBluetoothAdapter()); + finish(null); + } + + public void disable() { + getBluetoothTestUtils().disable(getBluetoothAdapter()); + finish(null); + } + + public void unpairAll() { + getBluetoothTestUtils().unpairAll(getBluetoothAdapter()); + finish(null); + } + + public void getName() { + String name = getBluetoothAdapter().getName(); + Bundle bundle = new Bundle(); + bundle.putString("name", name); + finish(bundle); + } + + public void finish(Bundle result) { + if (result == null) { + result = new Bundle(); + } + finish(Activity.RESULT_OK, result); + } +} diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java index 4858be8..8fbd214 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java @@ -34,6 +34,7 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; public class BluetoothTestUtils extends Assert { @@ -893,6 +894,17 @@ public class BluetoothTestUtils extends Assert { } /** + * Deletes all pairings of remote devices + * @param adapter the BT adapter + */ + public void unpairAll(BluetoothAdapter adapter) { + Set<BluetoothDevice> devices = adapter.getBondedDevices(); + for (BluetoothDevice device : devices) { + unpair(adapter, device); + } + } + + /** * Connects a profile from the local device to a remote device and checks to make sure that the * profile is connected and that the correct actions were broadcast. * diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd index 3173ff1..762d30c 100644 --- a/docs/html/guide/topics/ui/actionbar.jd +++ b/docs/html/guide/topics/ui/actionbar.jd @@ -1145,7 +1145,7 @@ defined in a resource looks like this:</p> <item>Venus</item> <item>Earth</item> </string-array> -</pre> +</resources> </pre> <p>The {@link android.widget.ArrayAdapter} returned by {@link diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 7c45682..4fbd2a4 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -297,8 +297,6 @@ JDrm::JDrm( } JDrm::~JDrm() { - mDrm.clear(); - JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mObject); @@ -363,6 +361,13 @@ void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) } } +void JDrm::disconnect() { + if (mDrm != NULL) { + mDrm->destroyPlugin(); + mDrm.clear(); + } +} + // static bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { @@ -527,6 +532,7 @@ static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) { sp<JDrm> drm = setDrm(env, thiz, NULL); if (drm != NULL) { drm->setListener(NULL); + drm->disconnect(); } } diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h index 620ad28..b7b8e5d 100644 --- a/media/jni/android_media_MediaDrm.h +++ b/media/jni/android_media_MediaDrm.h @@ -47,6 +47,8 @@ struct JDrm : public BnDrmClient { void notify(DrmPlugin::EventType, int extra, const Parcel *obj); status_t setListener(const sp<DrmListener>& listener); + void disconnect(); + protected: virtual ~JDrm(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 98cbe7d..d09ee96 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7078,6 +7078,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (r == null) { return null; } + if (callback == null) { + throw new IllegalArgumentException("callback must not be null"); + } return mStackSupervisor.createActivityContainer(r, callback); } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index a27288a..5a9e690 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -139,7 +139,7 @@ final class ActivityRecord { boolean forceNewConfig; // force re-create with new config next time int launchCount; // count of launches since last state long lastLaunchTime; // time of last lauch of this activity - ArrayList<ActivityStack> mChildContainers = new ArrayList<ActivityStack>(); + ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>(); String stringName; // for caching of toString(). diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 42e1a37..e4b196e 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -36,6 +36,8 @@ import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; +import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE; + import com.android.internal.os.BatteryStatsImpl; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService.ItemMatcher; @@ -1028,9 +1030,9 @@ final class ActivityStack { private void setVisibile(ActivityRecord r, boolean visible) { r.visible = visible; mWindowManager.setAppVisibility(r.appToken, visible); - final ArrayList<ActivityStack> containers = r.mChildContainers; + final ArrayList<ActivityContainer> containers = r.mChildContainers; for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) { - ActivityContainer container = containers.get(containerNdx).mActivityContainer; + ActivityContainer container = containers.get(containerNdx); container.setVisible(visible); } } @@ -1231,6 +1233,7 @@ final class ActivityStack { * occurred and the activity will be notified immediately. */ void notifyActivityDrawnLocked(ActivityRecord r) { + mActivityContainer.setDrawn(); if ((r == null) || (mUndrawnActivitiesBelowTopTranslucent.remove(r) && mUndrawnActivitiesBelowTopTranslucent.isEmpty())) { @@ -1271,7 +1274,8 @@ final class ActivityStack { if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen(""); ActivityRecord parent = mActivityContainer.mParentActivity; - if (parent != null && parent.state != ActivityState.RESUMED) { + if ((parent != null && parent.state != ActivityState.RESUMED) || + !mActivityContainer.isAttached()) { // Do not resume this stack if its parent is not resumed. // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st. return false; @@ -2552,6 +2556,20 @@ final class ActivityStack { return r; } + void finishAllActivitiesLocked() { + for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { + final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.finishing) { + continue; + } + Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r); + finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false); + } + } + } + final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode, Intent resultData) { final ActivityRecord srec = ActivityRecord.forToken(token); @@ -2787,7 +2805,6 @@ final class ActivityStack { } if (activityRemoved) { mStackSupervisor.resumeTopActivitiesLocked(); - } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index efa3ad49..71924b0 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -95,7 +95,6 @@ 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; @@ -224,11 +223,11 @@ public final class ActivityStackSupervisor implements DisplayListener { // TODO: Add listener for removal of references. /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */ - SparseArray<WeakReference<ActivityContainer>> mActivityContainers = - new SparseArray<WeakReference<ActivityContainer>>(); + SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>(); /** Mapping from displayId to display current state */ - private SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<ActivityDisplay>(); + private final SparseArray<ActivityDisplay> mActivityDisplays = + new SparseArray<ActivityDisplay>(); InputManagerInternal mInputManagerInternal; @@ -260,7 +259,7 @@ public final class ActivityStackSupervisor implements DisplayListener { mActivityDisplays.put(displayId, activityDisplay); } - createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY); + createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY); mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); @@ -1378,7 +1377,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } // Need to create an app stack for this user. - int stackId = createStackOnDisplay(null, getNextStackId(), Display.DEFAULT_DISPLAY); + int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY); if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r + " stackId=" + stackId); mFocusedStack = getStack(stackId); @@ -2127,14 +2126,9 @@ public final class ActivityStackSupervisor implements DisplayListener { } ActivityStack getStack(int stackId) { - WeakReference<ActivityContainer> weakReference = mActivityContainers.get(stackId); - if (weakReference != null) { - ActivityContainer activityContainer = weakReference.get(); - if (activityContainer != null) { - return activityContainer.mStack; - } else { - mActivityContainers.remove(stackId); - } + ActivityContainer activityContainer = mActivityContainers.get(stackId); + if (activityContainer != null) { + return activityContainer.mStack; } return null; } @@ -2164,49 +2158,26 @@ public final class ActivityStackSupervisor implements DisplayListener { return null; } - ActivityContainer createActivityContainer(ActivityRecord parentActivity, int stackId, - IActivityContainerCallback callback) { - ActivityContainer activityContainer = new ActivityContainer(parentActivity, stackId, - callback); - mActivityContainers.put(stackId, new WeakReference<ActivityContainer>(activityContainer)); - if (parentActivity != null) { - parentActivity.mChildContainers.add(activityContainer.mStack); - } - return activityContainer; - } - ActivityContainer createActivityContainer(ActivityRecord parentActivity, IActivityContainerCallback callback) { - return createActivityContainer(parentActivity, getNextStackId(), callback); + ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback); + mActivityContainers.put(activityContainer.mStackId, activityContainer); + parentActivity.mChildContainers.add(activityContainer); + return activityContainer; } void removeChildActivityContainers(ActivityRecord parentActivity) { - for (int ndx = mActivityContainers.size() - 1; ndx >= 0; --ndx) { - final ActivityContainer container = mActivityContainers.valueAt(ndx).get(); - if (container == null) { - mActivityContainers.removeAt(ndx); - continue; - } - if (container.mParentActivity != parentActivity) { - continue; - } - - ActivityStack stack = container.mStack; - ActivityRecord top = stack.topRunningNonDelayedActivityLocked(null); - if (top != null) { - // TODO: Make sure the next activity doesn't start up when top is destroyed. - stack.destroyActivityLocked(top, true, true, "stack parent destroyed"); - } - mActivityContainers.removeAt(ndx); - container.detachLocked(); + final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers; + for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) { + ActivityContainer container = childStacks.remove(containerNdx); + container.release(); } } void deleteActivityContainer(IActivityContainer container) { ActivityContainer activityContainer = (ActivityContainer)container; if (activityContainer != null) { - activityContainer.mStack.destroyActivitiesLocked(null, true, - "deleteActivityContainer"); + activityContainer.mStack.finishAllActivitiesLocked(); final ActivityRecord parent = activityContainer.mParentActivity; if (parent != null) { parent.mChildContainers.remove(activityContainer); @@ -2217,14 +2188,14 @@ public final class ActivityStackSupervisor implements DisplayListener { } } - private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) { + private int createStackOnDisplay(int stackId, int displayId) { ActivityDisplay activityDisplay = mActivityDisplays.get(displayId); if (activityDisplay == null) { return -1; } - ActivityContainer activityContainer = - createActivityContainer(parentActivity, stackId, null); + ActivityContainer activityContainer = new ActivityContainer(stackId); + mActivityContainers.put(stackId, activityContainer); activityContainer.attachToDisplayLocked(activityDisplay); return stackId; } @@ -2306,9 +2277,9 @@ public final class ActivityStackSupervisor implements DisplayListener { } boolean shutdownLocked(int timeout) { - boolean timedout = false; goingToSleepLocked(); + boolean timedout = false; final long endTime = System.currentTimeMillis() + timeout; while (true) { boolean cantShutdown = false; @@ -2967,24 +2938,26 @@ public final class ActivityStackSupervisor implements DisplayListener { class ActivityContainer extends IActivityContainer.Stub { final int mStackId; - final IActivityContainerCallback mCallback; + IActivityContainerCallback mCallback = null; final ActivityStack mStack; - final ActivityRecord mParentActivity; - final String mIdString; + ActivityRecord mParentActivity = null; + String mIdString; boolean mVisible = true; /** Display this ActivityStack is currently on. Null if not attached to a Display. */ ActivityDisplay mActivityDisplay; - ActivityContainer(ActivityRecord parentActivity, int stackId, - IActivityContainerCallback callback) { + final static int CONTAINER_STATE_HAS_SURFACE = 0; + final static int CONTAINER_STATE_NO_SURFACE = 1; + final static int CONTAINER_STATE_FINISHING = 2; + int mContainerState = CONTAINER_STATE_HAS_SURFACE; + + ActivityContainer(int stackId) { synchronized (mService) { mStackId = stackId; mStack = new ActivityStack(this); - mParentActivity = parentActivity; - mCallback = callback; - mIdString = "ActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}"; + mIdString = "ActivtyContainer{" + mStackId + "}"; if (DEBUG_STACK) Slog.d(TAG, "Creating " + this); } } @@ -3034,6 +3007,14 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + @Override + public void release() { + mContainerState = CONTAINER_STATE_FINISHING; + mStack.finishAllActivitiesLocked(); + detachLocked(); + mWindowManager.removeStack(mStackId); + } + private void detachLocked() { if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display=" + mActivityDisplay + " Callers=" + Debug.getCallers(2)); @@ -3047,13 +3028,6 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void detachFromDisplay() { - synchronized (mService) { - detachLocked(); - } - } - - @Override public final int startActivity(Intent intent) { mService.enforceNotIsolatedCaller("ActivityContainer.startActivity"); int userId = mService.handleIncomingUser(Binder.getCallingPid(), @@ -3086,23 +3060,8 @@ public final class ActivityStackSupervisor implements DisplayListener { } @Override - public void attachToSurface(Surface surface, int width, int height, int density) { + public void setSurface(Surface surface, int width, int height, int density) { mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface"); - - final long origId = Binder.clearCallingIdentity(); - try { - synchronized (mService) { - ActivityDisplay activityDisplay = - new ActivityDisplay(surface, width, height, density); - mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay); - attachToDisplayLocked(activityDisplay); - mStack.resumeTopActivityLocked(null); - } - if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display=" - + mActivityDisplay); - } finally { - Binder.restoreCallingIdentity(origId); - } } ActivityStackSupervisor getOuter() { @@ -3121,6 +3080,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + // TODO: Make sure every change to ActivityRecord.visible results in a call to this. void setVisible(boolean visible) { if (mVisible != visible) { mVisible = visible; @@ -3131,52 +3091,114 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + void setDrawn() { + } + @Override public String toString() { return mIdString + (mActivityDisplay == null ? "N" : "A"); } } + private class VirtualActivityContainer extends ActivityContainer { + Surface mSurface; + boolean mDrawn = false; + + VirtualActivityContainer(ActivityRecord parent, IActivityContainerCallback callback) { + super(getNextStackId()); + mParentActivity = parent; + mCallback = callback; + mContainerState = CONTAINER_STATE_NO_SURFACE; + mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}"; + } + + @Override + public void setSurface(Surface surface, int width, int height, 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); + } + } + } + + private void setSurfaceLocked(Surface surface, int width, int height, int density) { + 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); +// } + } + + setSurfaceIfReady(); + + if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display=" + + virtualActivityDisplay); + } + + @Override + void setDrawn() { + synchronized (mService) { + mDrawn = true; + setSurfaceIfReady(); + } + } + + private void setSurfaceIfReady() { + if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn + + " mContainerState=" + mContainerState + " mSurface=" + mSurface); + if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) { + ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface); + mContainerState = CONTAINER_STATE_HAS_SURFACE; + } + } + } + /** Exactly one of these classes per Display in the system. Capable of holding zero or more * attached {@link ActivityStack}s */ - final class ActivityDisplay { + class ActivityDisplay { /** Actual Display this object tracks. */ int mDisplayId; Display mDisplay; DisplayInfo mDisplayInfo = new DisplayInfo(); - Surface mSurface; /** All of the stacks on this display. Order matters, topmost stack is in front of all other * 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() { + } ActivityDisplay(int displayId) { init(mDisplayManager.getDisplay(displayId)); } - ActivityDisplay(Surface surface, int width, int height, int density) { - DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); - long ident = Binder.clearCallingIdentity(); - try { - mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, - VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface, - DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | - DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); - } finally { - Binder.restoreCallingIdentity(ident); - } - - init(mVirtualDisplay.getDisplay()); - mSurface = surface; - - mWindowManager.handleDisplayAdded(mDisplayId); - } - - private void init(Display display) { + void init(Display display) { mDisplay = display; mDisplayId = display.getDisplayId(); mDisplay.getDisplayInfo(mDisplayInfo); @@ -3192,11 +3214,6 @@ public final class ActivityStackSupervisor implements DisplayListener { if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack + " from displayId=" + mDisplayId); mStacks.remove(stack); - if (mStacks.isEmpty() && mVirtualDisplay != null) { - mVirtualDisplay.release(); - mVirtualDisplay = null; - } - mSurface.release(); } void getBounds(Point bounds) { @@ -3207,8 +3224,42 @@ public final class ActivityStackSupervisor implements DisplayListener { @Override public String toString() { - return "ActivityDisplay={" + mDisplayId + (mVirtualDisplay == null ? "" : "V") - + " numStacks=" + mStacks.size() + "}"; + return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}"; + } + } + + class VirtualActivityDisplay extends ActivityDisplay { + VirtualDisplay mVirtualDisplay; + + VirtualActivityDisplay(int width, int height, int density) { + DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); + mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, VIRTUAL_DISPLAY_BASE_NAME, + width, height, density, null, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | + DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); + + init(mVirtualDisplay.getDisplay()); + + mWindowManager.handleDisplayAdded(mDisplayId); + } + + void setSurface(Surface surface) { + if (mVirtualDisplay != null) { + mVirtualDisplay.setSurface(surface); + } + } + + @Override + void detachActivitiesLocked(ActivityStack stack) { + super.detachActivitiesLocked(stack); + if (mVirtualDisplay != null) { + mVirtualDisplay.release(); + mVirtualDisplay = null; + } + } + + @Override + public String toString() { + return "VirtualActivityDisplay={" + mDisplayId + "}"; } } } |
