Merge "Add null check in showLockTaskToast" into nyc-dev
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 4a1aff7..02eb4d3 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -284,7 +284,7 @@
     }
 
     public boolean startExitBackTransition(final Activity activity) {
-        if (mEnteringNames == null) {
+        if (mEnteringNames == null || mCalledExitCoordinator != null) {
             return false;
         } else {
             if (!mHasExited) {
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 02dcc5c..2ae437e 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -28,12 +28,12 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 
 import libcore.util.ZoneInfoDB;
 
 import java.io.IOException;
-import java.util.WeakHashMap;
 
 /**
  * This class provides access to the system alarm services.  These allow you
@@ -244,7 +244,7 @@
 
     // Tracking of the OnAlarmListener -> wrapper mapping, for cancel() support.
     // Access is synchronized on the AlarmManager class object.
-    private static WeakHashMap<OnAlarmListener, ListenerWrapper> sWrappers;
+    private static ArrayMap<OnAlarmListener, ListenerWrapper> sWrappers;
 
     /**
      * package private on purpose
@@ -631,7 +631,7 @@
         if (listener != null) {
             synchronized (AlarmManager.class) {
                 if (sWrappers == null) {
-                    sWrappers = new WeakHashMap<OnAlarmListener, ListenerWrapper>();
+                    sWrappers = new ArrayMap<OnAlarmListener, ListenerWrapper>();
                 }
 
                 recipientWrapper = sWrappers.get(listener);
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index a599584..8bf1e9a 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -150,6 +150,7 @@
                 }
             };
             decor.getViewTreeObserver().addOnPreDrawListener(mViewsReadyListener);
+            decor.invalidate();
         }
     }
 
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 6e6baea..3069e5a 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -21,9 +21,9 @@
 import android.graphics.Canvas;
 import android.graphics.Outline;
 import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
 
@@ -230,6 +230,7 @@
     public void setOnClickListener(@Nullable OnClickListener l) {
         mExpandClickListener = l;
         setOnTouchListener(mExpandClickListener != null ? mTouchListener : null);
+        setFocusable(l != null);
         updateTouchListener();
     }
 
@@ -379,6 +380,19 @@
         return this;
     }
 
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        if (mExpandClickListener != null) {
+            AccessibilityNodeInfo.AccessibilityAction expand
+                    = new AccessibilityNodeInfo.AccessibilityAction(
+                    AccessibilityNodeInfo.ACTION_CLICK,
+                    getContext().getString(
+                            com.android.internal.R.string.expand_action_accessibility));
+            info.addAction(expand);
+        }
+    }
+
     public ImageView getExpandButton() {
         return mExpandButton;
     }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 28ade80..b331be7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2675,19 +2675,49 @@
         return (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK ? 0 : mPaddingBottom;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected void internalSetPadding(int left, int top, int right, int bottom) {
+        super.internalSetPadding(left, top, right, bottom);
+        if (isLayoutRequested()) {
+            handleBoundsChange();
+        }
+    }
+
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        if (getChildCount() > 0) {
-            mDataChanged = true;
-            rememberSyncState();
-        }
-
+        handleBoundsChange();
         if (mFastScroll != null) {
             mFastScroll.onSizeChanged(w, h, oldw, oldh);
         }
     }
 
     /**
+     * Called when bounds of the AbsListView are changed. AbsListView marks data set as changed
+     * and force layouts all children that don't have exact measure specs.
+     * <p>
+     * This invalidation is necessary, otherwise, AbsListView may think the children are valid and
+     * fail to relayout them properly to accommodate for new bounds.
+     */
+    void handleBoundsChange() {
+        final int childCount = getChildCount();
+        if (childCount > 0) {
+            mDataChanged = true;
+            rememberSyncState();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final ViewGroup.LayoutParams lp = child.getLayoutParams();
+                // force layout child unless it has exact specs
+                if (lp == null || lp.width < 1 || lp.height < 1) {
+                    child.forceLayout();
+                }
+            }
+        }
+    }
+
+    /**
      * @return True if the current touch mode requires that we draw the selector in the pressed
      *         state.
      */
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index f596636..a065219 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -45,6 +45,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.Shader;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
@@ -907,10 +908,12 @@
         if (getBackground() != drawable) {
             setBackgroundDrawable(drawable);
             if (drawable != null) {
-                mResizingBackgroundDrawable = drawable;
+                mResizingBackgroundDrawable = enforceNonTranslucentBackground(drawable,
+                        mWindow.isTranslucent() || mWindow.isShowingWallpaper());
             } else {
                 mResizingBackgroundDrawable = getResizingBackgroundDrawable(
-                        getContext(), 0, mWindow.mBackgroundFallbackResource);
+                        getContext(), 0, mWindow.mBackgroundFallbackResource,
+                        mWindow.isTranslucent() || mWindow.isShowingWallpaper());
             }
             if (mResizingBackgroundDrawable != null) {
                 mResizingBackgroundDrawable.getPadding(mBackgroundPadding);
@@ -1785,7 +1788,8 @@
     private void loadBackgroundDrawablesIfNeeded() {
         if (mResizingBackgroundDrawable == null) {
             mResizingBackgroundDrawable = getResizingBackgroundDrawable(getContext(),
-                    mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
+                    mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource,
+                    mWindow.isTranslucent() || mWindow.isShowingWallpaper());
             if (mResizingBackgroundDrawable == null) {
                 // We shouldn't really get here as the background fallback should be always
                 // available since it is defaulted by the system.
@@ -1893,21 +1897,41 @@
      * user is resizing the window of an activity in multi-window mode.
      */
     public static Drawable getResizingBackgroundDrawable(Context context, int backgroundRes,
-            int backgroundFallbackRes) {
+            int backgroundFallbackRes, boolean windowTranslucent) {
         if (backgroundRes != 0) {
             final Drawable drawable = context.getDrawable(backgroundRes);
             if (drawable != null) {
-                return drawable;
+                return enforceNonTranslucentBackground(drawable, windowTranslucent);
             }
         }
 
         if (backgroundFallbackRes != 0) {
             final Drawable fallbackDrawable = context.getDrawable(backgroundFallbackRes);
             if (fallbackDrawable != null) {
-                return fallbackDrawable;
+                return enforceNonTranslucentBackground(fallbackDrawable, windowTranslucent);
             }
         }
-        return null;
+        return new ColorDrawable(Color.BLACK);
+    }
+
+    /**
+     * Enforces a drawable to be non-translucent to act as a background if needed, i.e. if the
+     * window is not translucent.
+     */
+    private static Drawable enforceNonTranslucentBackground(Drawable drawable,
+            boolean windowTranslucent) {
+        if (!windowTranslucent && drawable instanceof ColorDrawable) {
+            ColorDrawable colorDrawable = (ColorDrawable) drawable;
+            int color = colorDrawable.getColor();
+            if (Color.alpha(color) != 255) {
+                ColorDrawable copy = (ColorDrawable) colorDrawable.getConstantState().newDrawable()
+                        .mutate();
+                copy.setColor(
+                        Color.argb(255, Color.red(color), Color.green(color), Color.blue(color)));
+                return copy;
+            }
+        }
+        return drawable;
     }
 
     /**
@@ -2037,7 +2061,7 @@
     private void drawResizingShadowIfNeeded(DisplayListCanvas canvas) {
         if (mResizeMode != RESIZE_MODE_DOCKED_DIVIDER || mWindow.mIsFloating
                 || mWindow.isTranslucent()
-                || (mWindow.getAttributes().flags & FLAG_SHOW_WALLPAPER) != 0) {
+                || mWindow.isShowingWallpaper()) {
             return;
         }
         canvas.save();
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 4f15ece..9ad750d 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -509,6 +509,13 @@
     }
 
     /**
+     * @return Whether the window is currently showing the wallpaper.
+     */
+    boolean isShowingWallpaper() {
+        return (getAttributes().flags & FLAG_SHOW_WALLPAPER) != 0;
+    }
+
+    /**
      * Return a LayoutInflater instance that can be used to inflate XML view layout
      * resources for use in this Window.
      *
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3a28822..4649e9d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4263,7 +4263,7 @@
     <string name="expand_button_content_description">Expand button</string>
 
     <!-- Accessibility action description on the expand button. -->
-    <string name="expand_action_accessibility">Click to expand</string>
+    <string name="expand_action_accessibility">toggle expansion</string>
 
     <!-- User visible name for USB MIDI Peripheral port -->
     <string name="usb_midi_peripheral_name">Android USB Peripheral Port</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9ab42a9..9dbe100 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2566,6 +2566,7 @@
 
   <!-- WallpaperManager config -->
   <java-symbol type="string" name="config_wallpaperCropperPackage" />
+  <java-symbol type="string" name="expand_action_accessibility" />
 
   <java-symbol type="id" name="textSpacerNoTitle" />
   <java-symbol type="id" name="titleDividerNoCustom" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 998eea5..aecda44 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -174,7 +174,6 @@
 
         <!-- Window attributes -->
         <item name="windowBackground">@drawable/screen_background_selector_dark</item>
-        <item name="windowBackgroundFallback">?attr/colorBackground</item>
         <item name="windowClipToOutline">false</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
diff --git a/docs/html/wear/preview/api-overview.jd b/docs/html/wear/preview/api-overview.jd
index 384cb0a..543313a 100644
--- a/docs/html/wear/preview/api-overview.jd
+++ b/docs/html/wear/preview/api-overview.jd
@@ -147,7 +147,7 @@
 <p> If you have a chat messaging app, your notifications should use
 {@code Notification.MessagingStyle}, which is new in Android 6.0. Wear 2.0 uses
 the chat messages included in a
-<a href="{docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
+<a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
  notification
 (see {@code addMessage()}) to provide a rich chat app-like experience in the
 expanded notification.
diff --git a/docs/html/wear/preview/features/notifications.jd b/docs/html/wear/preview/features/notifications.jd
index 0962eb4..75f9fee 100644
--- a/docs/html/wear/preview/features/notifications.jd
+++ b/docs/html/wear/preview/features/notifications.jd
@@ -41,7 +41,7 @@
 </p>
 
 <p><img src="{@docRoot}wear/preview/images/comparison_diagram.png" /> </p>
-<p><b>Figure 1.</b> Comparison of the same notification in Android Wear 1.x and 2.0.</p> 
+<p><b>Figure 1.</b> Comparison of the same notification in Android Wear 1.x and 2.0.</p>
 
 <p>Some of the visual updates include:</p>
 <ul>
@@ -73,7 +73,7 @@
 
 <li><strong>Updated horizontal swipe gesture on a notification</strong>:
   To dismiss a notification in Wear 2.0, the user swipes horizontally in either
-  direction. So if your notification instructs the user to swipe left or right, 
+  direction. So if your notification instructs the user to swipe left or right,
   you must update the text of your notification.
 </li>
 </ul>
@@ -82,13 +82,14 @@
   substantial additional content and actions for each notification.
 </p>
 <p>When you <a href="{@docRoot}training/wearables/notifications/pages.html">specify additional content pages</a>
- and actions for a notification, those are available to the user within the 
- expanded notification. Each expanded notification follows 
+ and actions for a notification, those are available to the user within the
+ expanded notification. Each expanded notification follows
  <a href="http://www.google.com/design/spec-wear">Material Design for Android Wear</a>,
   so the user gets an app-like experience.
 </p>
-<p><img src="{@docRoot}wear/preview/images/expanded_diagram.png" /> </p>
-<p><b>Figure 2</b>. An expanded notification with content and actions.</p>
+
+
+<h3 id="expanded">Expanded notifications</h3>
 <p>If the first action in the expanded notification has a
 <a href=" {@docRoot}reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
   (e.g., a Reply action), then the choices you set with <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a>
@@ -102,7 +103,7 @@
   <li>The notification is generated by an app on the paired phone and
     bridged to Wear.
   </li>
-  <li>The notification does not have a 
+  <li>The notification does not have a
   <a href="http://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">{@code contentIntent}</a>.
   </li>
 </ul>
@@ -126,9 +127,11 @@
 <p>
  Expanded Notifications allow you to include additional content and actions
    for a notification. You choose the level of detail that your app's notifications
-    will provide; however be judicious with the amount of detail you include in a 
-    notification. 
+    will provide; however be judicious with the amount of detail you include in a
+    notification.
 </p>
+<img src="{@docRoot}wear/preview/images/expanded_diagram.png" height="340"
+  style="float:left;margin:10px 20px 0 0" />
 <h4>Adding additional content</h4>
 To show additional content in your expanded notification, see <a href="{@docRoot}training/wearables/notifications/pages.html">Adding Pages to a Notification</a>.</p>
 <p>Additional content pages are stacked vertically in the expanded notification
@@ -151,34 +154,36 @@
 
 <p>If you have a chat messaging app, your notifications should use
 <a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>,
- which is new in Android 6.0. Wear 2.0 uses the chat messages included
+ which is new in Android N. Wear 2.0 uses the chat messages included
   in a <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notification 
+
   (see <a href="{@docRoot}preview/features/notification-updates.html#style">{@code addMessage()}</a>) to provide
   a rich chat app-like experience in the expanded notification.
 </p>
-<p class="note">Note: <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> 
+
+<p class="note">Note: <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a>
 expanded notifications require that you have at least version 1.5.0.2861804 of the
   <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app">Android Wear app</a>
   on your paired Android phone. That version will be available within the next
   few weeks in the Play Store.
 </p>
+
 <h3 id="smart-reply">Smart Reply</h3>
-<p>Wear 2.0 also introduces <i>Smart Reply</i> for <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notifications.
+<img src="{@docRoot}wear/preview/images/messaging_style.png" height="420"
+  style="float:right;margin:10px 20px 0 0" />
+<p>Wear 2.0 also introduces <i>Smart Reply</i>
+for <a href="{@docRoot}preview/features/notification-updates.html#style">{@code MessagingStyle}</a> notifications.
   Smart Reply provides the user with contextually relevant, touchable choices in
   the expanded notification and in {@code RemoteInput}. These augment the fixed
-  list of choices that the developer provides in 
+  list of choices that the developer provides in
    <a href="http://developer.android.com/reference/android/support/v4/app/RemoteInput.html">{@code RemoteInput}</a>
-    using the 
+    using the
     <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
 </p>
 <p>By enabling Smart Reply for your MessagingStyle notifications,
   you provide users with a fast (single tap), discreet (no speaking aloud), and
   reliable way to respond to chat messages.
 </p>
-<p><img src="{@docRoot}wear/preview/images/messaging_style.png" /></p>
-<p><b>Figure 3</b>. The expanded notification includes contextually relevant
-  Smart Reply responses below the primary action.
-</p>
 
 <p>Responses generated by Smart Reply are shown in addition to those set using the
   <a href="{@docRoot}reference/android/support/v4/app/RemoteInput.Builder.html#setChoices(java.lang.CharSequence[])">{@code setChoices()}</a> method.
@@ -189,7 +194,7 @@
 <ol>
   <li>Use <a href="{@docRoot}preview/features/notification-updates.html#style">{@code Notification.MessagingStyle}</a>.
   </li>
-  <li>Call the method 
+  <li>Call the method
   <a href="{@docRoot}wear/preview/start.html#get_the_preview_reference_documentation">{@code setAllowGeneratedReplies()}</a>
    for the notification action.</li>
   <li>Ensure that the notification action has a
@@ -222,8 +227,9 @@
  .setSmallIcon(R.drawable.new_message)
  .setLargeIcon(aBitmap)
  // 2) set the style to MessagingStyle
- .setStyle(new NotificationCompat.MessagingStyle(resources.getString(R.string.reply_name)).addMessage(messages[0].getText(), messages[0].getTime(), messages[0].getSender())
-  .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getSender()))
+ .setStyle(new NotificationCompat.MessagingStyle(resources.getString(R.string.reply_name))
+ .addMessage(messages[0].getText(), messages[0].getTime(), messages[0].getSender())
+ .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getSender()))
 
 
 // 3) add an action with RemoteInput
diff --git a/docs/html/wear/preview/images/comparison_diagram.png b/docs/html/wear/preview/images/comparison_diagram.png
index 7dbf65f2..4bcf10e 100644
--- a/docs/html/wear/preview/images/comparison_diagram.png
+++ b/docs/html/wear/preview/images/comparison_diagram.png
Binary files differ
diff --git a/docs/html/wear/preview/images/messaging_style.png b/docs/html/wear/preview/images/messaging_style.png
index 966e524..a3bf109 100644
--- a/docs/html/wear/preview/images/messaging_style.png
+++ b/docs/html/wear/preview/images/messaging_style.png
Binary files differ
diff --git a/docs/html/wear/preview/images/messaging_style_diagram.png b/docs/html/wear/preview/images/messaging_style_diagram.png
deleted file mode 100644
index 3b21c7973..0000000
--- a/docs/html/wear/preview/images/messaging_style_diagram.png
+++ /dev/null
Binary files differ
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 59c1065..8b3f172 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -805,27 +805,21 @@
     // Note that we don't use op->paint in this function - it's never set on a LayerOp
     OffscreenBuffer* buffer = *op.layerHandle;
 
-    if (CC_UNLIKELY(!buffer)) {
-        // Layer was not allocated, which can occur if there were no draw ops inside. We draw the
-        // equivalent by drawing a rect with the same layer properties (alpha/xfer/filter).
-        int color = SkColorSetA(SK_ColorTRANSPARENT, op.alpha * 255);
-        renderRectForLayer(renderer, op, state,
-                color, op.mode, op.colorFilter);
-    } else {
-        float layerAlpha = op.alpha * state.alpha;
-        Glop glop;
-        GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
-                .setRoundRectClipState(state.roundRectClipState)
-                .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount)
-                .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
-                .setTransform(state.computedState.transform, TransformFlags::None)
-                .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
-                        Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
-                .build();
-        renderer.renderGlop(state, glop);
-    }
+    if (CC_UNLIKELY(!buffer)) return;
 
-    if (buffer && !buffer->hasRenderedSinceRepaint) {
+    float layerAlpha = op.alpha * state.alpha;
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount)
+            .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
+            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+                    Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
+            .build();
+    renderer.renderGlop(state, glop);
+
+    if (!buffer->hasRenderedSinceRepaint) {
         buffer->hasRenderedSinceRepaint = true;
         if (CC_UNLIKELY(Properties::debugLayersUpdates)) {
             // render debug layer highlight
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index 01d3d70..6b7b721 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -53,7 +53,7 @@
 typedef void (*TestBakedOpReceiver)(BakedOpRenderer&, const BakedOpState&);
 
 static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op,
-        std::function<void(const Glop& glop)> glopVerifier) {
+        std::function<void(const Glop& glop)> glopVerifier, int expectedGlopCount = 1) {
     // Create op, and wrap with basic state.
     LinearAllocator allocator;
     auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 100));
@@ -61,8 +61,8 @@
     ASSERT_NE(nullptr, state);
 
     int glopCount = 0;
-    auto glopReceiver = [&glopVerifier, &glopCount] (const Glop& glop) {
-        ASSERT_EQ(glopCount++, 0) << "Only one Glop expected";
+    auto glopReceiver = [&glopVerifier, &glopCount, &expectedGlopCount] (const Glop& glop) {
+        ASSERT_LE(glopCount++, expectedGlopCount) << expectedGlopCount << "glop(s) expected";
         glopVerifier(glop);
     };
     ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver);
@@ -75,7 +75,8 @@
     static TestBakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
 #undef X
     unmergedReceivers[op->opId](renderer, *state);
-    ASSERT_EQ(1, glopCount) << "Exactly one Glop expected";
+    ASSERT_EQ(expectedGlopCount, glopCount) << "Exactly " << expectedGlopCount
+            << "Glop(s) expected";
 }
 
 RENDERTHREAD_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) {
@@ -119,12 +120,8 @@
     OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
     LayerOp op(Rect(10, 10), Matrix4::identity(), nullptr, &layerPaint, &buffer);
     testUnmergedGlopDispatch(renderThread, &op, [&renderThread] (const Glop& glop) {
-        // rect glop is dispatched with paint props applied
-        EXPECT_EQ(renderThread.renderState().meshState().getUnitQuadVBO(),
-                glop.mesh.vertices.bufferObject) << "Unit quad should be drawn";
-        EXPECT_EQ(nullptr, glop.fill.texture.texture) << "Should be no texture when layer is null";
-        EXPECT_FLOAT_EQ(128 / 255.0f, glop.fill.color.a) << "Rect quad should use op alpha";
-    });
+        ADD_FAILURE() << "Nothing should happen";
+    }, 0);
 }
 
 static int getGlopTransformFlags(renderthread::RenderThread& renderThread, RecordedOp* op) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 57c14e9..b82f8dd 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -86,17 +86,26 @@
         if (mState.restored) {
             if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData());
         } else if (!mState.stack.isEmpty()) {
-            // If a non-empty stack is present in our state it was read (presumably)
+            // If a non-empty stack is present in our state, it was read (presumably)
             // from EXTRA_STACK intent extra. In this case, we'll skip other means of
-            // loading or restoring the stack.
+            // loading or restoring the stack (like URI).
             //
-            // When restoring from a stack, if a URI is present, it should only ever
-            // be a launch URI, or a fake Uri from notifications.
-            // Launch URIs support sensible activity management, but don't specify a real
-            // content target.
-            if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
-            assert(uri == null || uri.getAuthority() == null ||
-                    LauncherActivity.isLaunchUri(uri));
+            // When restoring from a stack, if a URI is present, it should only ever be:
+            // -- a launch URI: Launch URIs support sensible activity management,
+            //    but don't specify a real content target)
+            // -- a fake Uri from notifications. These URIs have no authority (TODO: details).
+            //
+            // Any other URI is *sorta* unexpected...except when browsing an archive
+            // in downloads.
+            if(uri != null
+                    && uri.getAuthority() != null
+                    && !uri.equals(mState.stack.peek())
+                    && !LauncherActivity.isLaunchUri(uri)) {
+                if (DEBUG) Log.w(TAG,
+                        "Launching with non-empty stack. Ignoring unexpected uri: " + uri);
+            } else {
+                if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
+            }
             refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE);
         } else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
             assert(uri != null);
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2758551..f7a169c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -594,6 +594,12 @@
     <!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "+ 3" [CHAR LIMIT=5] -->
     <string name="notification_group_overflow_indicator">+ <xliff:g id="number" example="3">%s</xliff:g></string>
 
+    <!-- Content description describing how many more notifications are in a group [CHAR LIMIT=NONE] -->
+    <plurals name="notification_group_overflow_description">
+        <item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> more notification inside.</item>
+        <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> more notifications inside.</item>
+    </plurals>
+
     <!-- Content description of button in notification inspector for system settings relating to
          notifications from this application [CHAR LIMIT=NONE] -->
     <string name="status_bar_notification_inspect_item_title">Notification settings</string>
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index d09587b..998f50f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -1064,6 +1064,14 @@
         int position = DockedDividerUtils.calculatePositionForBounds(event.initialRect,
                 mDockSide, mDividerSize);
         mEntranceAnimationRunning = true;
+
+        // Insets might not have been fetched yet, so fetch manually if needed.
+        if (mStableInsets.isEmpty()) {
+            SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+            mSnapAlgorithm = null;
+            initializeSnapAlgorithm();
+        }
+
         resizeStack(position, mSnapAlgorithm.getMiddleTarget().position,
                 mSnapAlgorithm.getMiddleTarget());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 6e9e830..b855b7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -18,10 +18,9 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.AnimationDrawable;
@@ -181,6 +180,7 @@
                     return object.getTranslation();
                 }
     };
+    private OnClickListener mOnClickListener;
 
     public boolean isGroupExpansionChanging() {
         if (isChildInGroup()) {
@@ -382,6 +382,7 @@
         mNotificationParent = childInGroup ? parent : null;
         mPrivateLayout.setIsChildInGroup(childInGroup);
         updateBackgroundForGroupState();
+        updateClickAndFocus();
         if (mNotificationParent != null) {
             mNotificationParent.updateBackgroundForGroupState();
         }
@@ -593,6 +594,24 @@
         mOnExpandClickListener = onExpandClickListener;
     }
 
+    @Override
+    public void setOnClickListener(@Nullable OnClickListener l) {
+        super.setOnClickListener(l);
+        mOnClickListener = l;
+        updateClickAndFocus();
+    }
+
+    private void updateClickAndFocus() {
+        boolean normalChild = !isChildInGroup() || isGroupExpanded();
+        boolean clickable = mOnClickListener != null && normalChild;
+        if (isFocusable() != normalChild) {
+            setFocusable(normalChild);
+        }
+        if (isClickable() != clickable) {
+            setClickable(clickable);
+        }
+    }
+
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
         mHeadsUpManager = headsUpManager;
     }
@@ -1315,6 +1334,7 @@
         if (mChildrenContainer != null) {
             mChildrenContainer.setChildrenExpanded(expanded);
         }
+        updateClickAndFocus();
     }
 
     public static void applyTint(View v, int color) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
index 8f2c81f..7373607 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
@@ -112,6 +112,10 @@
         if (!text.equals(reusableView.getText())) {
             reusableView.setText(text);
         }
+        String contentDescription = String.format(mContext.getResources().getQuantityString(
+                R.plurals.notification_group_overflow_description, number), number);
+
+        reusableView.setContentDescription(contentDescription);
         return reusableView;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index a0f1bc2..ba191cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -670,6 +670,11 @@
         if (mNotificationHeader != null) {
             mNotificationHeader.setExpanded(childrenExpanded);
         }
+        final int count = mChildren.size();
+        for (int childIdx = 0; childIdx < count; childIdx++) {
+            ExpandableNotificationRow child = mChildren.get(childIdx);
+            child.setChildrenExpanded(childrenExpanded, false);
+        }
     }
 
     public void setNotificationParent(ExpandableNotificationRow parent) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6a8c8b0..dcd9b0c 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2201,11 +2201,11 @@
                     // If the app is null, then it was probably removed because the process died,
                     // otherwise wtf
                     if (r.app != null) {
-                        Slog.wtfStack(TAG, "Service done with onDestroy, but not inDestroying: "
+                        Slog.w(TAG, "Service done with onDestroy, but not inDestroying: "
                                 + r + ", app=" + r.app);
                     }
                 } else if (r.executeNesting != 1) {
-                    Slog.wtfStack(TAG, "Service done with onDestroy, but executeNesting="
+                    Slog.w(TAG, "Service done with onDestroy, but executeNesting="
                             + r.executeNesting + ": " + r);
                     // Fake it to keep from ANR due to orphaned entry.
                     r.executeNesting = 1;
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 4fd1350..31528e5 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -223,10 +223,11 @@
      * stop executing.
      */
     JobStatus getRunningJob() {
+        final JobStatus job;
         synchronized (mLock) {
-            return mRunningJob == null ?
-                    null : new JobStatus(mRunningJob);
+            job = mRunningJob;
         }
+        return job == null ? null : new JobStatus(job);
     }
 
     /** Called externally when a job that was scheduled for execution should be cancelled. */
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b5a8bf3..a8b1a4a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2582,6 +2582,9 @@
         }
         if (notification.actions != null) {
             for (Notification.Action action: notification.actions) {
+                if (action.actionIntent == null) {
+                    continue;
+                }
                 am.setPendingIntentWhitelistDuration(action.actionIntent.getTarget(), duration);
                 setPendingIntentWhitelistDuration(am, duration, action.getExtras());
                 final RemoteInput[] remoteInputs = action.getRemoteInputs();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a2bdde4..eb4d755 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2395,6 +2395,10 @@
             mPromoteSystemApps =
                     mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
 
+            // When upgrading from pre-N, we need to handle package extraction like first boot,
+            // as there is no profiling data available.
+            mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
+
             // save off the names of pre-existing system packages prior to scanning; we don't
             // want to automatically grant runtime permissions for new system apps
             if (mPromoteSystemApps) {
@@ -2407,11 +2411,6 @@
                 }
             }
 
-            // When upgrading from pre-N, we need to handle package extraction like first boot,
-            // as there is no profiling data available.
-            mIsPreNUpgrade = !mSettings.isNWorkDone();
-            mSettings.setNWorkDone();
-
             // Collect vendor overlay packages.
             // (Do this before scanning any apps.)
             // For security and version matching reason, only consider
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 75bd35c..dfd6dfe 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -191,7 +191,6 @@
     private static final String TAG_DEFAULT_BROWSER = "default-browser";
     private static final String TAG_DEFAULT_DIALER = "default-dialer";
     private static final String TAG_VERSION = "version";
-    private static final String TAG_N_WORK = "n-work";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_USER = "user";
@@ -398,17 +397,6 @@
 
     public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
 
-    /**
-     * Used to track whether N+ work has been done. This is similar to the file-system level
-     * and denotes that first-boot or upgrade-to-N work has been done.
-     *
-     * Note: the flag has been added to a) allow tracking while an API level check is impossible
-     *       and b) to merge upgrade as well as first boot (because the flag is false, by default).
-     *
-     * STOPSHIP: b/27872764
-     */
-    private boolean mIsNWorkDone = false;
-
     Settings(Object lock) {
         this(Environment.getDataDirectory(), lock);
     }
@@ -2396,10 +2384,6 @@
 
             mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
 
-            serializer.startTag(null, TAG_N_WORK);
-            serializer.attribute(null, ATTR_DONE, Boolean.toString(mIsNWorkDone));
-            serializer.endTag(null, TAG_N_WORK);
-
             serializer.endTag(null, "packages");
 
             serializer.endDocument();
@@ -2937,8 +2921,6 @@
                     ver.sdkVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
                     ver.databaseVersion = XmlUtils.readIntAttribute(parser, ATTR_SDK_VERSION);
                     ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
-                } else if (TAG_N_WORK.equals(tagName)) {
-                    mIsNWorkDone = XmlUtils.readBooleanAttribute(parser, ATTR_DONE, false);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
                             + parser.getName());
@@ -4233,14 +4215,6 @@
         return res;
     }
 
-    public boolean isNWorkDone() {
-        return mIsNWorkDone;
-    }
-
-    void setNWorkDone() {
-        mIsNWorkDone = true;
-    }
-
     static void printFlags(PrintWriter pw, int val, Object[] spec) {
         pw.print("[ ");
         for (int i=0; i<spec.length; i+=2) {