Merge "Import translations. DO NOT MERGE" into nyc-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6424520..04883a9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5021,6 +5021,9 @@
 
         final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
         if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
+            // This cache location probably points at credential-encrypted
+            // storage which may not be accessible yet; assign it anyway instead
+            // of pointing at device-encrypted storage.
             final File cacheDir = appContext.getCacheDir();
             if (cacheDir != null) {
                 // Provide a usable directory for temporary files
@@ -5030,8 +5033,12 @@
                         + "due to missing cache directory");
             }
 
-            // Use codeCacheDir to store generated/compiled graphics code and jit profiling data.
-            final File codeCacheDir = appContext.getCodeCacheDir();
+            // Setup a location to store generated/compiled graphics code and
+            // JIT profiling data. Note that this data is stored in a
+            // device-encrypted storage area, so these caches must never contain
+            // user sensitive user data.
+            final Context deviceContext = appContext.createDeviceEncryptedStorageContext();
+            final File codeCacheDir = deviceContext.getCodeCacheDir();
             if (codeCacheDir != null) {
                 setupGraphicsSupport(data.info, codeCacheDir);
                 setupJitProfileSupport(data.info, codeCacheDir);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 89d4931..eec503b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -58,6 +58,9 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.storage.IMountService;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -482,21 +485,20 @@
         return f.delete();
     }
 
-    // Common-path handling of app data dir creation
+    /**
+     * Common-path handling of app data dir creation
+     */
     private static File ensurePrivateDirExists(File file) {
         if (!file.exists()) {
-            if (!file.mkdirs()) {
-                if (file.exists()) {
-                    // spurious failure; probably racing with another process for this app
-                    return file;
+            try {
+                Os.mkdir(file.getAbsolutePath(), 0771);
+            } catch (ErrnoException e) {
+                if (e.errno == OsConstants.EEXIST) {
+                    // We must have raced with someone; that's okay
+                } else {
+                    Log.w(TAG, "Failed to ensure " + file + ": " + e.getMessage());
                 }
-                Log.w(TAG, "Failed to ensure directory " + file.getAbsolutePath());
-                return null;
             }
-            FileUtils.setPermissions(
-                    file.getPath(),
-                    FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-                    -1, -1);
         }
         return file;
     }
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 287c696..b2e8d33 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -57,9 +57,9 @@
  * tag <code>fade</code>, along with the standard
  * attributes of {@link android.R.styleable#Fade} and
  * {@link android.R.styleable#Transition}.</p>
-
  */
 public class Fade extends Visibility {
+    static final String PROPNAME_TRANSITION_ALPHA = "android:fade:transitionAlpha";
 
     private static boolean DBG = Transition.DBG && false;
 
@@ -105,6 +105,13 @@
         setMode(fadingMode);
     }
 
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        super.captureStartValues(transitionValues);
+        transitionValues.values.put(PROPNAME_TRANSITION_ALPHA,
+                transitionValues.view.getTransitionAlpha());
+    }
+
     /**
      * Utility method to handle creating and running the Animator.
      */
@@ -119,7 +126,6 @@
         }
         final FadeAnimatorListener listener = new FadeAnimatorListener(view);
         anim.addListener(listener);
-        anim.addPauseListener(listener);
         addListener(new TransitionListenerAdapter() {
             @Override
             public void onTransitionEnd(Transition transition) {
@@ -138,18 +144,28 @@
             Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
                     startView + ", " + view);
         }
-        return createAnimation(view, 0, 1);
+        float startAlpha = 0;
+        if (startValues != null) {
+            startAlpha = (Float) startValues.values.get(PROPNAME_TRANSITION_ALPHA);
+            if (startAlpha == 1) {
+                startAlpha = 0;
+            }
+        }
+        return createAnimation(view, startAlpha, 1);
     }
 
     @Override
     public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues,
             TransitionValues endValues) {
-        return createAnimation(view, 1, 0);
+        float startAlpha = 1;
+        if (startValues != null) {
+            startAlpha = (Float) startValues.values.get(PROPNAME_TRANSITION_ALPHA);
+        }
+        return createAnimation(view, startAlpha, 0);
     }
 
     private static class FadeAnimatorListener extends AnimatorListenerAdapter {
         private final View mView;
-        private float mPausedAlpha = -1;
         private boolean mLayerTypeChanged = false;
 
         public FadeAnimatorListener(View view) {
@@ -171,16 +187,5 @@
                 mView.setLayerType(View.LAYER_TYPE_NONE, null);
             }
         }
-
-        @Override
-        public void onAnimationPause(Animator animator) {
-            mPausedAlpha = mView.getTransitionAlpha();
-            mView.setTransitionAlpha(1);
-        }
-
-        @Override
-        public void onAnimationResume(Animator animator) {
-            mView.setTransitionAlpha(mPausedAlpha);
-        }
     }
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 1740f07..5b9930b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -166,6 +166,7 @@
             in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
             int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
     void setAppVisibility(IBinder token, boolean visible);
+    void notifyAppStopped(IBinder token);
     void startAppFreezingScreen(IBinder token, int configChanges);
     void stopAppFreezingScreen(IBinder token, boolean force);
     void removeAppToken(IBinder token);
diff --git a/core/tests/coretests/res/layout/animator_set_squares.xml b/core/tests/coretests/res/layout/animator_set_squares.xml
index 23e6eea..6888248f 100644
--- a/core/tests/coretests/res/layout/animator_set_squares.xml
+++ b/core/tests/coretests/res/layout/animator_set_squares.xml
@@ -4,7 +4,8 @@
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:background="@android:color/white"
-    android:orientation="horizontal">
+    android:orientation="horizontal"
+    android:id="@+id/container">
     <View
         android:layout_width="50dp"
         android:layout_height="50dp"
diff --git a/core/tests/coretests/src/android/transition/FadeTransitionTest.java b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
new file mode 100644
index 0000000..dc60423
--- /dev/null
+++ b/core/tests/coretests/src/android/transition/FadeTransitionTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2016 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.transition;
+
+import android.animation.AnimatorSetActivity;
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.transition.Transition.TransitionListener;
+import android.transition.Transition.TransitionListenerAdapter;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static android.support.test.espresso.Espresso.onView;
+
+public class FadeTransitionTest extends ActivityInstrumentationTestCase2<AnimatorSetActivity> {
+    Activity mActivity;
+    public FadeTransitionTest() {
+        super(AnimatorSetActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        mActivity = getActivity();
+    }
+
+    @SmallTest
+    public void testFadeOutAndIn() throws Throwable {
+        View square1 = mActivity.findViewById(R.id.square1);
+        Fade fadeOut = new Fade(Fade.MODE_OUT);
+        TransitionLatch latch = setVisibilityInTransition(fadeOut, R.id.square1, View.INVISIBLE);
+        assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS));
+        assertEquals(View.VISIBLE, square1.getVisibility());
+        Thread.sleep(100);
+        assertFalse(square1.getTransitionAlpha() == 0 || square1.getTransitionAlpha() == 1);
+        assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS));
+        assertEquals(1.0f, square1.getTransitionAlpha());
+        assertEquals(View.INVISIBLE, square1.getVisibility());
+
+        Fade fadeIn = new Fade(Fade.MODE_IN);
+        latch = setVisibilityInTransition(fadeIn, R.id.square1, View.VISIBLE);
+        assertTrue(latch.startLatch.await(200, TimeUnit.MILLISECONDS));
+        assertEquals(View.VISIBLE, square1.getVisibility());
+        Thread.sleep(100);
+        final float transitionAlpha = square1.getTransitionAlpha();
+        assertTrue("expecting transitionAlpha to be between 0 and 1. Was " + transitionAlpha,
+                transitionAlpha > 0 && transitionAlpha < 1);
+        assertTrue(latch.endLatch.await(400, TimeUnit.MILLISECONDS));
+        assertEquals(1.0f, square1.getTransitionAlpha());
+        assertEquals(View.VISIBLE, square1.getVisibility());
+    }
+
+    @SmallTest
+    public void testFadeOutInterrupt() throws Throwable {
+        View square1 = mActivity.findViewById(R.id.square1);
+        Fade fadeOut = new Fade(Fade.MODE_OUT);
+        FadeValueCheck fadeOutValueCheck = new FadeValueCheck(square1);
+        fadeOut.addListener(fadeOutValueCheck);
+        TransitionLatch outLatch = setVisibilityInTransition(fadeOut, R.id.square1, View.INVISIBLE);
+        assertTrue(outLatch.startLatch.await(200, TimeUnit.MILLISECONDS));
+        Thread.sleep(100);
+
+        Fade fadeIn = new Fade(Fade.MODE_IN);
+        FadeValueCheck fadeInValueCheck = new FadeValueCheck(square1);
+        fadeIn.addListener(fadeInValueCheck);
+        TransitionLatch inLatch = setVisibilityInTransition(fadeIn, R.id.square1, View.VISIBLE);
+        assertTrue(inLatch.startLatch.await(200, TimeUnit.MILLISECONDS));
+
+        assertEquals(fadeOutValueCheck.pauseTransitionAlpha, fadeInValueCheck.startTransitionAlpha);
+        assertTrue("expecting transitionAlpha to be between 0 and 1. Was " +
+                fadeOutValueCheck.pauseTransitionAlpha,
+                fadeOutValueCheck.pauseTransitionAlpha > 0 &&
+                        fadeOutValueCheck.pauseTransitionAlpha < 1);
+
+        assertTrue(inLatch.endLatch.await(400, TimeUnit.MILLISECONDS));
+        assertEquals(1.0f, square1.getTransitionAlpha());
+        assertEquals(View.VISIBLE, square1.getVisibility());
+    }
+
+    @SmallTest
+    public void testFadeInInterrupt() throws Throwable {
+        final View square1 = mActivity.findViewById(R.id.square1);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                square1.setVisibility(View.INVISIBLE);
+            }
+        });
+        Fade fadeIn = new Fade(Fade.MODE_IN);
+        FadeValueCheck fadeInValueCheck = new FadeValueCheck(square1);
+        fadeIn.addListener(fadeInValueCheck);
+        TransitionLatch inLatch = setVisibilityInTransition(fadeIn, R.id.square1, View.VISIBLE);
+        assertTrue(inLatch.startLatch.await(200, TimeUnit.MILLISECONDS));
+        Thread.sleep(100);
+
+        Fade fadeOut = new Fade(Fade.MODE_OUT);
+        FadeValueCheck fadeOutValueCheck = new FadeValueCheck(square1);
+        fadeOut.addListener(fadeOutValueCheck);
+        TransitionLatch outLatch = setVisibilityInTransition(fadeOut, R.id.square1, View.INVISIBLE);
+        assertTrue(outLatch.startLatch.await(200, TimeUnit.MILLISECONDS));
+
+        assertEquals(fadeOutValueCheck.pauseTransitionAlpha, fadeInValueCheck.startTransitionAlpha);
+        assertTrue("expecting transitionAlpha to be between 0 and 1. Was " +
+                        fadeInValueCheck.pauseTransitionAlpha,
+                fadeInValueCheck.pauseTransitionAlpha > 0 &&
+                        fadeInValueCheck.pauseTransitionAlpha < 1);
+
+        assertTrue(outLatch.endLatch.await(400, TimeUnit.MILLISECONDS));
+        assertEquals(1.0f, square1.getTransitionAlpha());
+        assertEquals(View.INVISIBLE, square1.getVisibility());
+    }
+
+    public TransitionLatch setVisibilityInTransition(final Transition transition, int viewId,
+            final int visibility) throws Throwable {
+        final ViewGroup sceneRoot = (ViewGroup) mActivity.findViewById(R.id.container);
+        final View view = sceneRoot.findViewById(viewId);
+        TransitionLatch latch = new TransitionLatch();
+        transition.addListener(latch);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(sceneRoot, transition);
+                view.setVisibility(visibility);
+            }
+        });
+        return latch;
+    }
+
+    public static class TransitionLatch implements TransitionListener {
+        public CountDownLatch startLatch = new CountDownLatch(1);
+        public CountDownLatch endLatch = new CountDownLatch(1);
+        public CountDownLatch cancelLatch = new CountDownLatch(1);
+        public CountDownLatch pauseLatch = new CountDownLatch(1);
+        public CountDownLatch resumeLatch = new CountDownLatch(1);
+
+        @Override
+        public void onTransitionStart(Transition transition) {
+            startLatch.countDown();
+        }
+
+        @Override
+        public void onTransitionEnd(Transition transition) {
+            endLatch.countDown();
+            transition.removeListener(this);
+        }
+
+        @Override
+        public void onTransitionCancel(Transition transition) {
+            cancelLatch.countDown();
+        }
+
+        @Override
+        public void onTransitionPause(Transition transition) {
+            pauseLatch.countDown();
+        }
+
+        @Override
+        public void onTransitionResume(Transition transition) {
+            resumeLatch.countDown();
+        }
+    }
+
+    private static class FadeValueCheck extends TransitionListenerAdapter {
+        public float startTransitionAlpha;
+        public float pauseTransitionAlpha;
+        private final View mView;
+
+        public FadeValueCheck(View view) {
+            mView = view;
+        }
+        @Override
+        public void onTransitionStart(Transition transition) {
+            startTransitionAlpha = mView.getTransitionAlpha();
+        }
+
+        @Override
+        public void onTransitionPause(Transition transition) {
+            pauseTransitionAlpha = mView.getTransitionAlpha();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c352fc8..9442da0 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1097,6 +1097,9 @@
             mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
             r.stopped = true;
             r.state = ActivityState.STOPPED;
+
+            mWindowManager.notifyAppStopped(r.appToken);
+
             if (getVisibleBehindActivity() == r) {
                 mStackSupervisor.requestVisibleBehindLocked(r, false);
             }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index fcb777b..8fa5d24 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2359,7 +2359,7 @@
                 }
 
                 final ApplicationInfo ai = pkg.pkg.applicationInfo;
-                final String dataPath = new File(ai.dataDir).getCanonicalPath();
+                final String dataPath = ai.dataDir;
                 final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
                 final int[] gids = pkg.getPermissionsState().computeGids(userIds);
 
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 7ec945d..5a502c1 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -127,6 +127,8 @@
 
     boolean mAlwaysFocusable;
 
+    boolean mAppStopped;
+
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
 
     AppWindowToken(WindowManagerService _service, IApplicationToken _token,
@@ -311,6 +313,47 @@
         }
     }
 
+    // Here we destroy surfaces which have been marked as eligible by the animator, taking care
+    // to ensure the client has finished with them. If the client could still be using them
+    // we will skip destruction and try again when the client has stopped.
+    void destroySurfaces() {
+        final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) allAppWindows.clone();
+        final DisplayContentList displayList = new DisplayContentList();
+        for (int i = allWindows.size() - 1; i >= 0; i--) {
+            final WindowState win = allWindows.get(i);
+            if (!win.mDestroying) {
+                continue;
+            }
+
+            if (!mAppStopped && !win.mClientRemoveRequested) {
+                return;
+            }
+
+            win.destroyOrSaveSurface();
+            if (win.mRemoveOnExit) {
+                win.mExiting = false;
+                service.removeWindowInnerLocked(win);
+            }
+            final DisplayContent displayContent = win.getDisplayContent();
+            if (displayContent != null && !displayList.contains(displayContent)) {
+                displayList.add(displayContent);
+            }
+            win.mDestroying = false;
+        }
+        for (int i = 0; i < displayList.size(); i++) {
+            final DisplayContent displayContent = displayList.get(i);
+            service.mLayersController.assignLayersLocked(displayContent.getWindowList());
+            displayContent.layoutNeeded = true;
+        }
+    }
+
+    // The application has stopped, so destroy any surfaces which were keeping alive
+    // in case they were still being used.
+    void notifyAppStopped() {
+        mAppStopped = true;
+        destroySurfaces();
+    }
+
     /**
      * Checks whether we should save surfaces for this app.
      *
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ae6c89a..3db16c7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2154,6 +2154,14 @@
             if (win == null) {
                 return;
             }
+            // We set this here instead of removeWindowLocked because we only want it to be
+            // true when the client has requested we remove the window. In other remove
+            // cases, we have to wait for activity stop to safely remove the window (as the
+            // client may still be using the surface). In this case though, the client has
+            // just dismissed a window (for example a Dialog) and activity stop isn't
+            // necessarily imminent, so we need to know not to wait for it after our
+            // hanimation (if applicable) finishes.
+            win.mClientRemoveRequested = true;
             removeWindowLocked(win);
         }
     }
@@ -4188,6 +4196,24 @@
     }
 
     @Override
+    public void notifyAppStopped(IBinder token) {
+        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
+                "notifyAppStopped()")) {
+            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+        }
+
+        synchronized(mWindowMap) {
+            final AppWindowToken wtoken;
+            wtoken = findAppWindowToken(token);
+            if (wtoken == null) {
+                Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
+                return;
+            }
+            wtoken.notifyAppStopped();
+        }
+    }
+
+    @Override
     public void setAppVisibility(IBinder token, boolean visible) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppVisibility()")) {
@@ -4210,6 +4236,7 @@
 
             mOpeningApps.remove(wtoken);
             mClosingApps.remove(wtoken);
+            wtoken.mAppStopped = false;
             wtoken.waitingToShow = false;
             wtoken.hiddenRequested = !visible;
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 880514c..114c212 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -386,6 +386,13 @@
     boolean mRemoved;
 
     /**
+     * Has the client requested we remove the window? In this case we know
+     * that we can dispose of it when we wish without further synchronization
+     * with the client
+     */
+    boolean mClientRemoveRequested;
+
+    /**
      * Temp for keeping track of windows that have been removed when
      * rebuilding window list.
      */
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c7c9cbf..0201296 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -471,16 +471,31 @@
         if (WindowManagerService.localLOGV) Slog.v(
                 TAG, "Exit animation finished in " + this
                 + ": remove=" + mWin.mRemoveOnExit);
-        if (hasSurface()) {
-            mService.mDestroySurface.add(mWin);
-            mWin.mDestroying = true;
-            hide("finishExit");
+
+
+        mWin.mDestroying = true;
+
+        // If we have an app token, we ask it to destroy the surface for us,
+        // so that it can take care to ensure the activity has actually stopped
+        // and the surface is not still in use. Otherwise we add the service to
+        // mDestroySurface and allow it to be processed in our next transaction.
+        if (mWin.mAppToken != null) {
+            if (hasSurface()) {
+                hide("finishExit");
+            }
+            mWin.mAppToken.destroySurfaces();
+        } else {
+            if (hasSurface()) {
+                mService.mDestroySurface.add(mWin);
+                hide("finishExit");
+            }
+            mWin.mExiting = false;
+            if (mWin.mRemoveOnExit) {
+                mService.mPendingRemove.add(mWin);
+                mWin.mRemoveOnExit = false;
+            }
         }
-        mWin.mExiting = false;
-        if (mWin.mRemoveOnExit) {
-            mService.mPendingRemove.add(mWin);
-            mWin.mRemoveOnExit = false;
-        }
+
         mWallpaperControllerLocked.hideWallpapers(mWin);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 2560c31..8d1b124 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -348,6 +348,11 @@
     }
 
     @Override
+    public void notifyAppStopped(IBinder token) throws RemoteException {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
     public void setEventDispatching(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
     }