Merge "ChooserActivity: Cannot start app that the icon overflows the layout" into nyc-mr1-dev
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/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;
+
         }
     }