Merge "QS: Make BT detail be more consistent with Settings" into nyc-mr1-dev
diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp
index 8a5c2c6..dbb76dc 100644
--- a/cmds/bootanimation/audioplay.cpp
+++ b/cmds/bootanimation/audioplay.cpp
@@ -158,16 +158,32 @@
     SLDataSink audioSnk = {&loc_outmix, NULL};
 
     // create audio player
-    const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
-    const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+    const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION};
+    const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
-            2, ids, req);
+            3, ids, req);
     if (result != SL_RESULT_SUCCESS) {
         ALOGE("sl CreateAudioPlayer failed with result %d", result);
         return false;
     }
     (void)result;
 
+    // Use the System stream for boot sound playback.
+    SLAndroidConfigurationItf playerConfig;
+    result = (*bqPlayerObject)->GetInterface(bqPlayerObject,
+        SL_IID_ANDROIDCONFIGURATION, &playerConfig);
+    if (result != SL_RESULT_SUCCESS) {
+        ALOGE("config GetInterface failed with result %d", result);
+        return false;
+    }
+    SLint32 streamType = SL_ANDROID_STREAM_SYSTEM;
+    result = (*playerConfig)->SetConfiguration(playerConfig,
+        SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
+    if (result != SL_RESULT_SUCCESS) {
+        ALOGE("SetConfiguration failed with result %d", result);
+        return false;
+    }
+
     // realize the player
     result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
     if (result != SL_RESULT_SUCCESS) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 2a40aeb..2b25b3f 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -618,7 +618,7 @@
         }
     }
 
-    private void setupTitle(ViewGroup topPanel) {
+    protected void setupTitle(ViewGroup topPanel) {
         if (mCustomTitleView != null && mShowTitle) {
             // Add the custom title view directly to the topPanel layout
             final LayoutParams lp = new LayoutParams(
@@ -701,7 +701,7 @@
         }
     }
 
-    private void setupButtons(ViewGroup buttonPanel) {
+    protected void setupButtons(ViewGroup buttonPanel) {
         int BIT_BUTTON_POSITIVE = 1;
         int BIT_BUTTON_NEGATIVE = 2;
         int BIT_BUTTON_NEUTRAL = 4;
diff --git a/core/java/com/android/internal/app/MicroAlertController.java b/core/java/com/android/internal/app/MicroAlertController.java
index 085b226..00fcd6f 100644
--- a/core/java/com/android/internal/app/MicroAlertController.java
+++ b/core/java/com/android/internal/app/MicroAlertController.java
@@ -82,4 +82,20 @@
             }
         }
     }
+
+    @Override
+    protected void setupTitle(ViewGroup topPanel) {
+        super.setupTitle(topPanel);
+        if (topPanel.getVisibility() == View.GONE) {
+            topPanel.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    @Override
+    protected void setupButtons(ViewGroup buttonPanel) {
+        super.setupButtons(buttonPanel);
+        if (buttonPanel.getVisibility() == View.GONE) {
+            buttonPanel.setVisibility(View.INVISIBLE);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 8b9d503..e84cc27 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -245,7 +245,7 @@
                 final float y = ev.getY();
                 mInitialTouchX = x;
                 mInitialTouchY = mLastTouchY = y;
-                mOpenOnClick = isListChildUnderClipped(x, y) && mCollapsibleHeight > 0;
+                mOpenOnClick = isListChildUnderClipped(x, y) && mCollapseOffset > 0;
             }
             break;
 
diff --git a/core/res/res/layout-watch/alert_dialog_material.xml b/core/res/res/layout-watch/alert_dialog_material.xml
index e627d42..a8bb204 100644
--- a/core/res/res/layout-watch/alert_dialog_material.xml
+++ b/core/res/res/layout-watch/alert_dialog_material.xml
@@ -21,6 +21,7 @@
         android:layout_height="match_parent">
     <ScrollView
             android:id="@+id/scrollView"
+            android:fillViewport="true"
             android:layout_width="match_parent"
             android:layout_height="match_parent">
         <LinearLayout
@@ -33,7 +34,8 @@
                     android:paddingRight="?dialogPreferredPadding"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:id="@+id/topPanel">
+                    android:id="@+id/topPanel"
+                    android:minHeight="@dimen/dialog_list_padding_top_no_title">
                 <include android:id="@+id/title_template"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
@@ -68,41 +70,33 @@
             <!-- Button Panel -->
             <FrameLayout
                     android:id="@+id/buttonPanel"
+                    android:minHeight="@dimen/dialog_list_padding_bottom_no_buttons"
+                    android:layout_weight="1"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content">
                 <LinearLayout
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:divider="?android:attr/dividerHorizontal"
-                        android:showDividers="beginning"
-                        android:dividerPadding="0dip"
                         android:orientation="vertical"
                         android:minHeight="@dimen/alert_dialog_button_bar_height"
                         android:paddingBottom="?dialogPreferredPadding"
                         style="?android:attr/buttonBarStyle"
-                        android:layoutDirection="locale"
                         android:measureWithLargestChild="true">
                     <Button android:id="@+id/button1"
                             android:layout_gravity="start"
                             android:layout_weight="1"
-                            android:layout_marginLeft="?dialogPreferredPadding"
-                            android:layout_marginRight="?dialogPreferredPadding"
                             style="?android:attr/buttonBarButtonStyle"
                             android:layout_width="match_parent"
                             android:layout_height="wrap_content" />
                     <Button android:id="@+id/button3"
                             android:layout_gravity="start"
                             android:layout_weight="1"
-                            android:layout_marginLeft="?dialogPreferredPadding"
-                            android:layout_marginRight="?dialogPreferredPadding"
                             style="?android:attr/buttonBarButtonStyle"
                             android:layout_width="match_parent"
                             android:layout_height="wrap_content" />
                     <Button android:id="@+id/button2"
                             android:layout_gravity="start"
                             android:layout_weight="1"
-                            android:layout_marginLeft="?dialogPreferredPadding"
-                            android:layout_marginRight="?dialogPreferredPadding"
                             style="?android:attr/buttonBarButtonStyle"
                             android:layout_width="match_parent"
                             android:layout_height="wrap_content" />
diff --git a/core/res/res/values-notround-watch/dimens_material.xml b/core/res/res/values-notround-watch/dimens_material.xml
index b02437b..9cacb11 100644
--- a/core/res/res/values-notround-watch/dimens_material.xml
+++ b/core/res/res/values-notround-watch/dimens_material.xml
@@ -20,4 +20,7 @@
     <dimen name="list_item_padding_horizontal_material">16dp</dimen>
     <dimen name="list_item_padding_start_material">16dp</dimen>
     <dimen name="list_item_padding_end_material">16dp</dimen>
+
+    <dimen name="dialog_list_padding_top_no_title">8dp</dimen>
+    <dimen name="dialog_list_padding_bottom_no_buttons">8dp</dimen>
 </resources>
diff --git a/core/res/res/values-round-watch/dimens_material.xml b/core/res/res/values-round-watch/dimens_material.xml
index db1f1f3..f2de4e0 100644
--- a/core/res/res/values-round-watch/dimens_material.xml
+++ b/core/res/res/values-round-watch/dimens_material.xml
@@ -20,4 +20,7 @@
     <dimen name="list_item_padding_horizontal_material">@dimen/screen_percentage_15</dimen>
     <dimen name="list_item_padding_start_material">@dimen/screen_percentage_15</dimen>
     <dimen name="list_item_padding_end_material">@dimen/screen_percentage_10</dimen>
+
+    <dimen name="dialog_list_padding_top_no_title">@dimen/screen_percentage_15</dimen>
+    <dimen name="dialog_list_padding_bottom_no_buttons">@dimen/screen_percentage_15</dimen>
 </resources>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index daeeca2..5c4c632 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -61,8 +61,13 @@
         <item name="breakStrategy">balanced</item>
     </style>
 
+    <style name="Widget.Material.ButtonBar" parent="Widget.Material.BaseButtonBar" />
+
     <!-- Alert dialog button bar button -->
     <style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Small">
+        <item name="paddingStart">@dimen/list_item_padding_start_material</item>
+        <item name="paddingEnd">@dimen/list_item_padding_end_material</item>
+        <item name="drawablePadding">8dp</item>
         <item name="gravity">center_vertical|left</item>
         <item name="minWidth">64dp</item>
         <item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index fad3488..1aae02b 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -543,7 +543,11 @@
         <item name="textOff">@string/capital_off</item>
     </style>
 
-    <style name="Widget.Material.ButtonBar">
+    <style name="Widget.Material.BaseButtonBar">
+        <item name="background">?attr/colorBackgroundFloating</item>
+    </style>
+
+    <style name="Widget.Material.ButtonBar" parent="Widget.Material.BaseButtonBar">
         <item name="background">@null</item>
     </style>
 
diff --git a/docs/html/distribute/engage/easy-signin.jd b/docs/html/distribute/engage/easy-signin.jd
index 924c5b4..5c04064 100644
--- a/docs/html/distribute/engage/easy-signin.jd
+++ b/docs/html/distribute/engage/easy-signin.jd
@@ -1,70 +1,66 @@
-page.title=Add Quick and Secure Google Sign-in
+page.title=Add Quick and Secure Google Sign-In
 page.metaDescription=Increase conversion rates while helping users minimize typing by letting users sign in with Google+.
 page.tags="google", "identity", "signin"
 page.image=images/cards/google-sign-in_2x.png
 
 @jd:body
 
-<p>Get people into your apps quickly and securely, using a registration system they
-already use and trust – their Google account. With minimal effort, you can increase
-registration and sign-in conversion by adding trusted registration system that's
-familiar to users, consistent across devices, and quick and easy to use.</p>
-
-<p>Get started <a href="https://developers.google.com/identity/sign-in/">integrating
-Google sign-in into your apps and games</a>.</p>
-
-<div class="wrap">
-  <div class="cols" style="margin-top:2em;">
-    <div class="col-3of12">
-      <h3>Quick and secure app access</h3>
-        <p>A secure authentication system that makes sign-in easy for your users by
-        letting them use their Google account, which they already use with Gmail,
-        Play, Google+, and other Google services.</p>
-    </div>
-    <div class="col-8of12 col-push-1of12">
-     <img src="{@docRoot}images/distribute/signin-secure.png" style="padding-top:1em;">
-    </div>
-  </div>
-
-  <div class="cols" style="margin-top:2em;">
-    <div class="col-3of12">
-      <h3>Seamless experience across screens</h3>
-      <p>Keep your users engaged, no matter what device they pick up or sit down at.
-      Offer a seamless app experience across devices and into your website, securely
-      from a one-time consent. </p>
-    </div>
-    <div class="col-8of12  col-push-1of12">
-      <img src="{@docRoot}images/distribute/signin-seamless.png" style="padding-top:1em;">
-    </div>
-  </div>
-
-  <div class="cols" style="margin-top:2em;">
-    <div class="col-3of12">
-      <h3>Help your users take action with Google</h3>
-        <p>Securely connect users with Google services and let them pay with Google
-        Wallet, share with Google contacts, save files to Drive, add events to
-        Calendar, and more.</p>
-    </div>
-    <div class="col-8of12 col-push-1of12">
-     <img src="{@docRoot}images/distribute/signin-apps.png" style="padding-top:1em;">
-    </div>
-  </div>
+<div class="figure">
+  <img src="{@docRoot}images/distribute/google-sign-in-banner.png" style="width:512px;">
 </div>
+<p>
+  Get customers into your apps quickly and securely using a registration system that they
+  already use and trust &ndash; their Google account. With minimal effort, you can increase
+  registration and sign-in conversion by adding a trusted registration system that's familiar
+  to users, consistent across devices, and quick and easy to use.
+</p>
 
+<h2 id="tips">Benefits</h2>
 
-<h2>Tips</h2>
+<p>These are some of the ways Sign-In can improve your app:</p>
 
 <ul>
-<li>Add <strong>over-the-air installs</strong> to your website. After signing in with Google
-  on the web, users will have the option to send your Android app to their device instantly,
-  without them ever leaving your website.</li>
-  <li>With Google sign-in, you can take advantage of other <strong>Google+ platform
-  features</strong> like adding a +1 button so users can make recommendations and the ability
-  to share rich content to the Google+ stream.</li>
+  <li>
+    <strong>Quick and secure app access</strong>: Google Sign-In is a secure authentication
+    system that makes sign-in easy for your users by letting them use their Google account,
+    which they already use with Gmail, Google Play, Google+, and other Google services.
+  </li>
+
+  <li>
+    <strong>Seamless experience across screens</strong>: Keep your users engaged, no matter
+    what device they choose. Offer a secure and seamless app experience across devices and
+    into your website, from a one-time consent.
+  </li>
+
+  <li>
+    <strong>Convenient access to Google services</strong>: Securely connect users with
+    Google services and let them pay with Google Wallet, share with Google Contacts, save files
+    to Google Drive, and add events to Google Calendar.
+  </li>
 </ul>
 
+<p>Get started integrating<a href="https://developers.google.com/identity/sign-in/">
+Google Sign-In</a> into your apps and games.</p>
 
-<h2 style="clear:both" id="related-resources">Related Resources</h2>
+<h2 id="tips">Tips</h2>
+
+<p>Here are some suggestions for enhancing the Sign-In user experience:</p>
+
+<ul>
+  <li>
+    Add <strong>over-the-air installs</strong> to your website. After signing in with Google
+    on the web, users have the option to send your Android app to their device instantly,
+    without ever leaving your website.
+  </li>
+
+  <li>
+    With Google Sign-In, you can take advantage of other <strong>Google+ platform
+    features</strong>, like adding a +1 button so users can make recommendations and have
+    the ability to share rich content to their Google+ streams.
+  </li>
+</ul>
+
+<h2 style="clear:both" id="related-resources">Related resources</h2>
 
 <div class="resource-widget resource-flow-layout col-13"
   data-query="collection:distribute/engage/gplus"
@@ -72,5 +68,3 @@
   data-cardsizes="9x3"
   data-maxresults="4">
 </div>
-
-
diff --git a/docs/html/images/distribute/google-sign-in-banner.png b/docs/html/images/distribute/google-sign-in-banner.png
new file mode 100644
index 0000000..ba04686
--- /dev/null
+++ b/docs/html/images/distribute/google-sign-in-banner.png
Binary files differ
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index 15485c4..5c42277 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -2982,7 +2982,7 @@
     "url": "https://developers.google.com/identity/sign-in/android/people",
     "timestamp": 1383243492000,
     "image": "images/cards/google-sign-in_2x.png",
-    "title": "Get user profile details",
+    "title": "Get User Profile Details",
     "summary": "After users sign-in with Google, you can access their age range, language, and public profile information.",
     "keywords": ["signin", "identity", "google"],
     "type": "distribute",
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index 48dc053..ba08d9b 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -765,6 +765,23 @@
   is returned, even if the encryption key is specific to the user or profile.
   </li>
 
+  <li>In Android N, several methods that would ordinarily affect the entire
+  device behave differently if the device has a work profile installed with a
+  separate work challenge. Rather than affecting the entire device, these
+  methods apply only to the work profile. (The complete list of such methods is
+  in the {@link android.app.admin.DevicePolicyManager#getParentProfileInstance
+  DevicePolicyManager.getParentProfileInstance()} documentation.) For example,
+  {@link android.app.admin.DevicePolicyManager#lockNow
+  DevicePolicyManager.lockNow()} locks just the work profile, instead of
+  locking the entire device. For each of these methods, you can get the old
+  behavior by calling the method on the parent instance of the
+  {@link android.app.admin.DevicePolicyManager}; you can get this parent by
+  calling {@link android.app.admin.DevicePolicyManager#getParentProfileInstance
+  DevicePolicyManager.getParentProfileInstance()}. So for example, if you call
+  the parent instance's {@link android.app.admin.DevicePolicyManager#lockNow}
+  method, the entire device is locked.
+  </li>
+
 </ul>
 
 <p>
diff --git a/docs/html/preview/features/notification-updates.jd b/docs/html/preview/features/notification-updates.jd
index af449cb..fd65e12 100644
--- a/docs/html/preview/features/notification-updates.jd
+++ b/docs/html/preview/features/notification-updates.jd
@@ -395,5 +395,6 @@
                  .addMessage("Hi", timestamp1, null) // Pass in null for user.
                  .addMessage("What's up?", timestamp2, "Coworker")
                  .addMessage("Not much", timestamp3, null)
-                 .addMessage("How about lunch?", timestamp4, "Coworker"));
+                 .addMessage("How about lunch?", timestamp4, "Coworker"))
+             .build();
 </pre>
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 8c20ddc..f36c00c 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -228,7 +228,7 @@
         if (exportResult.resultCode != KeyStore.NO_ERROR) {
             throw (UnrecoverableKeyException)
                     new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
-                    .initCause(KeyStore.getKeyStoreException(errorCode));
+                    .initCause(KeyStore.getKeyStoreException(exportResult.resultCode));
         }
         final byte[] x509EncodedPublicKey = exportResult.exportData;
 
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 3d6643d..5dfac95 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -25,8 +25,8 @@
     <!-- Content notification indicating a bugreport is being updated before it can be shared, asking the user to wait [CHAR LIMIT=50] -->
     <string name="bugreport_updating_wait">Please wait\u2026</string>
 
-    <!-- Text of notification indicating that swipe left will share the captured bugreport. [CHAR LIMIT=100] -->
-    <string name="bugreport_finished_text" product="watch">Swipe left to share your bug report</string>
+    <!-- Text of notification indicating that bugreport will appear on the phone. [CHAR LIMIT=100] -->
+    <string name="bugreport_finished_text" product="watch">The bug report will appear on the phone shortly</string>
     <!-- Text of notification indicating that tapping will share the captured bugreport. [CHAR LIMIT=100] -->
     <string name="bugreport_finished_text" product="default">Tap to share your bug report</string>
     <!-- Text of notification indicating that swipe left will share the captured bugreport, but giving user the option to wait for the screenshot. [CHAR LIMIT=100] -->
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 6bc4df7..f04df4b 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -212,6 +212,8 @@
 
     private static final Bundle sNotificationBundle = new Bundle();
 
+    private boolean mIsWatch;
+
     @Override
     public void onCreate() {
         mContext = getApplicationContext();
@@ -225,6 +227,9 @@
                 Log.w(TAG, "Could not create directory " + mScreenshotsDir);
             }
         }
+        final Configuration conf = mContext.getResources().getConfiguration();
+        mIsWatch = (conf.uiMode & Configuration.UI_MODE_TYPE_MASK) ==
+                Configuration.UI_MODE_TYPE_WATCH;
     }
 
     @Override
@@ -439,56 +444,68 @@
             return;
         }
 
-        final NumberFormat nf = NumberFormat.getPercentInstance();
-        nf.setMinimumFractionDigits(2);
-        nf.setMaximumFractionDigits(2);
-        final String percentageText = nf.format((double) info.progress / info.max);
-        final Action cancelAction = new Action.Builder(null, mContext.getString(
-                com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
-        final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
-        infoIntent.setAction(INTENT_BUGREPORT_INFO_LAUNCH);
-        infoIntent.putExtra(EXTRA_ID, info.id);
-        final PendingIntent infoPendingIntent =
-                PendingIntent.getService(mContext, info.id, infoIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
-        final Action infoAction = new Action.Builder(null,
-                mContext.getString(R.string.bugreport_info_action),
-                infoPendingIntent).build();
-        final Intent screenshotIntent = new Intent(mContext, BugreportProgressService.class);
-        screenshotIntent.setAction(INTENT_BUGREPORT_SCREENSHOT);
-        screenshotIntent.putExtra(EXTRA_ID, info.id);
-        PendingIntent screenshotPendingIntent = mTakingScreenshot ? null : PendingIntent
-                .getService(mContext, info.id, screenshotIntent,
-                        PendingIntent.FLAG_UPDATE_CURRENT);
-        final Action screenshotAction = new Action.Builder(null,
-                mContext.getString(R.string.bugreport_screenshot_action),
-                screenshotPendingIntent).build();
-
-        final String title = mContext.getString(R.string.bugreport_in_progress_title, info.id);
-
-        final String name =
-                info.name != null ? info.name : mContext.getString(R.string.bugreport_unnamed);
-
-        final Notification notification = newBaseNotification(mContext)
-                .setContentTitle(title)
-                .setTicker(title)
-                .setContentText(name)
-                .setProgress(info.max, info.progress, false)
-                .setOngoing(true)
-                .setContentIntent(infoPendingIntent)
-                .setActions(infoAction, screenshotAction, cancelAction)
-                .build();
-
         if (info.finished) {
             Log.w(TAG, "Not sending progress notification because bugreport has finished already ("
                     + info + ")");
             return;
         }
+
+        final NumberFormat nf = NumberFormat.getPercentInstance();
+        nf.setMinimumFractionDigits(2);
+        nf.setMaximumFractionDigits(2);
+        final String percentageText = nf.format((double) info.progress / info.max);
+
+        String title = mContext.getString(R.string.bugreport_in_progress_title, info.id);
+
+        // TODO: Remove this workaround when notification progress is implemented on Wear.
+        if (mIsWatch) {
+            nf.setMinimumFractionDigits(0);
+            nf.setMaximumFractionDigits(0);
+            final String watchPercentageText = nf.format((double) info.progress / info.max);
+            title = title + "\n" + watchPercentageText;
+        }
+
+        final String name =
+                info.name != null ? info.name : mContext.getString(R.string.bugreport_unnamed);
+
+        final Notification.Builder builder = newBaseNotification(mContext)
+                .setContentTitle(title)
+                .setTicker(title)
+                .setContentText(name)
+                .setProgress(info.max, info.progress, false)
+                .setOngoing(true);
+
+        // Wear bugreport doesn't need the bug info dialog, screenshot and cancel action.
+        if (!mIsWatch) {
+            final Action cancelAction = new Action.Builder(null, mContext.getString(
+                    com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
+            final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
+            infoIntent.setAction(INTENT_BUGREPORT_INFO_LAUNCH);
+            infoIntent.putExtra(EXTRA_ID, info.id);
+            final PendingIntent infoPendingIntent =
+                    PendingIntent.getService(mContext, info.id, infoIntent,
+                    PendingIntent.FLAG_UPDATE_CURRENT);
+            final Action infoAction = new Action.Builder(null,
+                    mContext.getString(R.string.bugreport_info_action),
+                    infoPendingIntent).build();
+            final Intent screenshotIntent = new Intent(mContext, BugreportProgressService.class);
+            screenshotIntent.setAction(INTENT_BUGREPORT_SCREENSHOT);
+            screenshotIntent.putExtra(EXTRA_ID, info.id);
+            PendingIntent screenshotPendingIntent = mTakingScreenshot ? null : PendingIntent
+                    .getService(mContext, info.id, screenshotIntent,
+                            PendingIntent.FLAG_UPDATE_CURRENT);
+            final Action screenshotAction = new Action.Builder(null,
+                    mContext.getString(R.string.bugreport_screenshot_action),
+                    screenshotPendingIntent).build();
+            builder.setContentIntent(infoPendingIntent)
+                .setActions(infoAction, screenshotAction, cancelAction);
+        }
+
         if (DEBUG) {
             Log.d(TAG, "Sending 'Progress' notification for id " + info.id + " (pid " + info.pid
                     + "): " + percentageText);
         }
-        sendForegroundabledNotification(info.id, notification);
+        sendForegroundabledNotification(info.id, builder.build());
     }
 
     private void sendForegroundabledNotification(int id, Notification notification) {
@@ -854,10 +871,7 @@
         // Stop running on foreground, otherwise share notification cannot be dismissed.
         stopForegroundWhenDone(id);
 
-        final Configuration conf = mContext.getResources().getConfiguration();
-        if ((conf.uiMode & Configuration.UI_MODE_TYPE_MASK) != Configuration.UI_MODE_TYPE_WATCH) {
-            triggerLocalNotification(mContext, info);
-        }
+        triggerLocalNotification(mContext, info);
     }
 
     /**
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 05207b9..402d9ad 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -16,17 +16,21 @@
 
 package com.android.wallpaperbackup;
 
+import static android.app.WallpaperManager.FLAG_LOCK;
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
 import android.app.WallpaperManager;
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.FullBackupDataOutput;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.graphics.Rect;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
-import android.system.Os;
 import android.util.Slog;
 import android.util.Xml;
 
@@ -40,7 +44,7 @@
 
 public class WallpaperBackupAgent extends BackupAgent {
     private static final String TAG = "WallpaperBackup";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     // NB: must be kept in sync with WallpaperManagerService but has no
     // compile-time visibility.
@@ -57,6 +61,11 @@
     static final String EMPTY_SENTINEL = "empty";
     static final String QUOTA_SENTINEL = "quota";
 
+    // Not-for-backup bookkeeping
+    static final String PREFS_NAME = "wbprefs.xml";
+    static final String SYSTEM_GENERATION = "system_gen";
+    static final String LOCK_GENERATION = "lock_gen";
+
     private File mWallpaperInfo;        // wallpaper metadata file
     private File mWallpaperFile;        // primary wallpaper image file
     private File mLockWallpaperFile;    // lock wallpaper image file
@@ -106,27 +115,48 @@
             // only back up the wallpaper if we've been told it's allowed
             if (mWm.isWallpaperBackupEligible()) {
                 if (DEBUG) {
-                    Slog.v(TAG, "Wallpaper is backup-eligible; linking & writing");
+                    Slog.v(TAG, "Wallpaper is backup-eligible");
                 }
 
-                // In case of prior muddled state
-                infoStage.delete();
-                imageStage.delete();
-                lockImageStage.delete();
+                SharedPreferences prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+                final int lastSysGeneration = prefs.getInt(SYSTEM_GENERATION, -1);
+                final int lastLockGeneration = prefs.getInt(LOCK_GENERATION, -1);
 
+                final int sysGeneration =
+                        mWm.getWallpaperIdForUser(FLAG_SYSTEM, UserHandle.USER_SYSTEM);
+                final int lockGeneration =
+                        mWm.getWallpaperIdForUser(FLAG_LOCK, UserHandle.USER_SYSTEM);
+                final boolean sysChanged = (sysGeneration != lastSysGeneration);
+                final boolean lockChanged = (lockGeneration != lastLockGeneration);
+
+                if (DEBUG) {
+                    Slog.v(TAG, "sysGen=" + sysGeneration + " : sysChanged=" + sysChanged);
+                    Slog.v(TAG, "lockGen=" + lockGeneration + " : lockChanged=" + lockChanged);
+                }
                 if (mWallpaperInfo.exists()) {
-                    Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
+                    if (sysChanged || lockChanged || !infoStage.exists()) {
+                        if (DEBUG) Slog.v(TAG, "New wallpaper configuration; copying");
+                        FileUtils.copyFileOrThrow(mWallpaperInfo, infoStage);
+                    }
                     fullBackupFile(infoStage, data);
                 }
                 if (mWallpaperFile.exists()) {
-                    Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
+                    if (sysChanged || !imageStage.exists()) {
+                        if (DEBUG) Slog.v(TAG, "New system wallpaper; copying");
+                        FileUtils.copyFileOrThrow(mWallpaperFile, imageStage);
+                    }
                     fullBackupFile(imageStage, data);
+                    prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
                 }
 
                 // Don't try to store the lock image if we overran our quota last time
                 if (mLockWallpaperFile.exists() && !mQuotaExceeded) {
-                    Os.link(mLockWallpaperFile.getCanonicalPath(), lockImageStage.getCanonicalPath());
+                    if (lockChanged || !lockImageStage.exists()) {
+                        if (DEBUG) Slog.v(TAG, "New lock wallpaper; copying");
+                        FileUtils.copyFileOrThrow(mLockWallpaperFile, lockImageStage);
+                    }
                     fullBackupFile(lockImageStage, data);
+                    prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
                 }
             } else {
                 if (DEBUG) {
@@ -136,13 +166,6 @@
         } catch (Exception e) {
             Slog.e(TAG, "Unable to back up wallpaper", e);
         } finally {
-            if (DEBUG) {
-                Slog.v(TAG, "Removing backup stage links");
-            }
-            infoStage.delete();
-            imageStage.delete();
-            lockImageStage.delete();
-
             // Even if this time we had to back off on attempting to store the lock image
             // due to exceeding the data quota, try again next time.  This will alternate
             // between "try both" and "only store the primary image" until either there
@@ -189,26 +212,30 @@
             Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
         } finally {
             if (DEBUG) {
-                Slog.v(TAG, "Removing restore stage files");
+                Slog.v(TAG, "Restore finished; clearing backup bookkeeping");
             }
             infoStage.delete();
             imageStage.delete();
             lockImageStage.delete();
+
+            SharedPreferences prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+            prefs.edit()
+                    .putInt(SYSTEM_GENERATION, -1)
+                    .putInt(LOCK_GENERATION, -1)
+                    .commit();
         }
     }
 
     private void restoreFromStage(File stage, File info, String hintTag, int which)
             throws IOException {
         if (stage.exists()) {
-            if (DEBUG) {
-                Slog.v(TAG, "Got restored wallpaper; applying which=" + which);
-            }
             // Parse the restored info file to find the crop hint.  Note that this currently
             // relies on a priori knowledge of the wallpaper info file schema.
             Rect cropHint = parseCropHint(info, hintTag);
             if (cropHint != null) {
+                Slog.i(TAG, "Got restored wallpaper; applying which=" + which);
                 if (DEBUG) {
-                    Slog.v(TAG, "Restored crop hint " + cropHint + "; now writing data");
+                    Slog.v(TAG, "Restored crop hint " + cropHint);
                 }
                 try (FileInputStream in = new FileInputStream(stage)) {
                     mWm.setStream(in, cropHint, true, which);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 67ff085..d426dd0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13604,7 +13604,7 @@
             sb.append("Process: ").append(processName).append("\n");
             int flags = process.info.flags;
             IPackageManager pm = AppGlobals.getPackageManager();
-            sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
+            sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n");
             for (int ip=0; ip<process.pkgList.size(); ip++) {
                 String pkg = process.pkgList.keyAt(ip);
                 sb.append("Package: ").append(pkg);
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 40ee5d8..7126cb5 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -215,7 +215,11 @@
      */
     public ArraySet<ComponentName> getInstalled(int userId) {
         synchronized (mLock) {
-            return mInstalledSet.get(userId);
+            ArraySet<ComponentName> ret = mInstalledSet.get(userId);
+            if (ret == null) {
+                return new ArraySet<ComponentName>();
+            }
+            return ret;
         }
     }
 
@@ -227,7 +231,12 @@
      */
     public ArraySet<ComponentName> getEnabled(int userId) {
         synchronized (mLock) {
-            return mEnabledSet.get(userId);
+            ArraySet<ComponentName> ret = mEnabledSet.get(userId);
+            if (ret == null) {
+                return new ArraySet<ComponentName>();
+            }
+            return ret;
+
         }
     }