Merge "Fix bad USB configuration under Developer Options" into mnc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5f1f14c..358eae9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -633,14 +633,11 @@
                 android:value="true" />
         </activity>
 
-        <!-- TODO: This should also be forwarded, but we can't use cross-profile intent filters -->
         <receiver android:name=".inputmethod.InputMethodDialogReceiver"
                 android:enabled="true">
             <intent-filter>
                 <action android:name="android.settings.SHOW_INPUT_METHOD_PICKER" />
             </intent-filter>
-            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
-                android:value="true" />
         </receiver>
 
         <activity android:name="Settings$UserDictionarySettingsActivity"
@@ -1433,6 +1430,7 @@
         <activity android:name=".fingerprint.FingerprintEnrollFindSensor" android:exported="false"/>
         <activity android:name=".fingerprint.FingerprintEnrollEnrolling" android:exported="false"/>
         <activity android:name=".fingerprint.FingerprintEnrollFinish" android:exported="false"/>
+        <activity android:name=".fingerprint.FingerprintEnrollIntroduction" android:exported="false"/>
 
         <!-- Note this must not be exported since it returns the password in the intent -->
         <activity android:name="ConfirmLockPattern$InternalActivity"
diff --git a/res/layout/empty_print_state.xml b/res/layout/empty_print_state.xml
index e97bb85..361bf3c 100644
--- a/res/layout/empty_print_state.xml
+++ b/res/layout/empty_print_state.xml
@@ -44,6 +44,18 @@
             android:textColor="?android:attr/textColorSecondary">
         </TextView>
 
+        <Button android:id="@+id/add_new_service"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:gravity="center"
+            android:visibility="gone"
+            style="?android:attr/buttonBarButtonStyle"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:text="@string/print_menu_item_add_service"
+            android:textAllCaps="true"
+            />
+
     </LinearLayout>
 
 </FrameLayout>
diff --git a/res/layout/fingerprint_enroll_introduction.xml b/res/layout/fingerprint_enroll_introduction.xml
new file mode 100644
index 0000000..df83bd9
--- /dev/null
+++ b/res/layout/fingerprint_enroll_introduction.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<com.android.setupwizardlib.SetupWizardLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/setup_wizard_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    style="@style/SetupWizardFingerprintStyle">
+
+    <LinearLayout
+        style="@style/SuwContentFrame"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <TextView
+            style="@style/TextAppearance.FingerprintMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/suw_description_margin_top"
+            android:text="@string/security_settings_fingerprint_enroll_introduction_message"/>
+
+        <TextView
+            style="@style/TextAppearance.FingerprintMessage"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="24dp"
+            android:text="@string/security_settings_fingerprint_enroll_introduction_message_warning"/>
+
+        <TextView
+            style="@style/TextAppearance.FingerprintLink"
+            android:id="@+id/learn_more_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:text="@string/security_settings_fingerprint_enroll_introduction_risk_link_text"/>
+
+        <View
+            android:layout_height="0dp"
+            android:layout_width="match_parent"
+            android:layout_weight="1"/>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="-12dp"
+            android:layout_marginBottom="4dp"
+            android:layout_gravity="end"
+            android:orientation="horizontal">
+
+            <Button
+                style="@style/Button.FingerprintButton"
+                android:id="@+id/cancel_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="8dp"
+                android:text="@string/security_settings_fingerprint_enroll_introduction_cancel" />
+
+            <Button
+                style="@style/Button.FingerprintButton"
+                android:id="@+id/next_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="end|center_vertical"
+                android:text="@string/security_settings_fingerprint_enroll_introduction_continue" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</com.android.setupwizardlib.SetupWizardLayout>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 1d58779..1b7caf7 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -309,6 +309,11 @@
         <item name="android:textColor">?android:attr/colorAccent</item>
     </style>
 
+    <style name="TextAppearance.FingerprintLink"
+           parent="TextAppearance.FingerprintMessage">
+        <item name="android:textColor">?android:attr/colorAccent</item>
+    </style>
+
     <style name="TextAppearance.FingerprintErrorText"
         parent="android:TextAppearance.Material.Caption">
         <item name="android:textColor">@color/warning</item>
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index 23f6812..6ab36c1 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -234,15 +234,18 @@
                                 authContext.getDrawable(desc.iconId), userHandle);
                     }
                 } catch (PackageManager.NameNotFoundException e) {
-                    Log.w(TAG, "No icon for account type " + desc.type);
+                    Log.w(TAG, "Bad package name for account type " + desc.type);
+                } catch (Resources.NotFoundException e) {
+                    Log.w(TAG, "Invalid icon id for account type " + desc.type, e);
+                }
+                if (icon == null) {
+                    icon = context.getPackageManager().getDefaultActivityIcon();
                 }
 
                 TextView child = (TextView)inflater.inflate(R.layout.master_clear_account,
                         contents, false);
                 child.setText(account.name);
-                if (icon != null) {
-                    child.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
-                }
+                child.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
                 contents.addView(child);
             }
         }
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 8f6c849..93bf1e0 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -17,8 +17,6 @@
 package com.android.settings;
 
 
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
@@ -54,8 +52,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settings.TrustAgentUtils.TrustAgentComponentInfo;
-import com.android.settings.fingerprint.FingerprintEnrollFindSensor;
-import com.android.settings.fingerprint.FingerprintEnrollOnboard;
+import com.android.settings.fingerprint.FingerprintEnrollIntroduction;
 import com.android.settings.fingerprint.FingerprintSettings;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Index;
@@ -65,6 +62,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+
 /**
  * Gesture lock pattern settings.
  */
@@ -358,12 +357,9 @@
                     R.plurals.security_settings_fingerprint_preference_summary,
                     fingerprintCount, fingerprintCount));
             clazz = FingerprintSettings.class.getName();
-        } else if (!hasPassword) {
-            // No fingerprints registered, launch into enrollment wizard.
-            clazz = FingerprintEnrollOnboard.class.getName();
         } else {
-            // Lock thingy is already set up, launch directly into find sensor step from wizard.
-            clazz = FingerprintEnrollFindSensor.class.getName();
+            clazz = FingerprintEnrollIntroduction.class.getName();
+            intent.putExtra(FingerprintEnrollIntroduction.EXTRA_HAS_PASSWORD, hasPassword);
         }
         intent.setClassName("com.android.settings", clazz);
         fingerprintPreference.setIntent(intent);
diff --git a/src/com/android/settings/accounts/AuthenticatorHelper.java b/src/com/android/settings/accounts/AuthenticatorHelper.java
index 86e0da5..56a689c 100644
--- a/src/com/android/settings/accounts/AuthenticatorHelper.java
+++ b/src/com/android/settings/accounts/AuthenticatorHelper.java
@@ -96,7 +96,8 @@
     /**
      * Gets an icon associated with a particular account type. If none found, return null.
      * @param accountType the type of account
-     * @return a drawable for the icon or null if one cannot be found.
+     * @return a drawable for the icon or a default icon returned by
+     * {@link PackageManager#getDefaultActivityIcon} if one cannot be found.
      */
     public Drawable getDrawableForType(Context context, final String accountType) {
         Drawable icon = null;
diff --git a/src/com/android/settings/accounts/ChooseAccountActivity.java b/src/com/android/settings/accounts/ChooseAccountActivity.java
index c4dace8..12077af 100644
--- a/src/com/android/settings/accounts/ChooseAccountActivity.java
+++ b/src/com/android/settings/accounts/ChooseAccountActivity.java
@@ -214,7 +214,8 @@
     /**
      * Gets an icon associated with a particular account type. If none found, return null.
      * @param accountType the type of account
-     * @return a drawable for the icon or null if one cannot be found.
+     * @return a drawable for the icon or a default icon returned by
+     * {@link PackageManager#getDefaultActivityIcon} if one cannot be found.
      */
     protected Drawable getDrawableForType(final String accountType) {
         Drawable icon = null;
@@ -225,14 +226,16 @@
                 icon = getPackageManager().getUserBadgedIcon(
                         authContext.getDrawable(desc.iconId), mUserHandle);
             } catch (PackageManager.NameNotFoundException e) {
-                // TODO: place holder icon for missing account icons?
                 Log.w(TAG, "No icon name for account type " + accountType);
             } catch (Resources.NotFoundException e) {
-                // TODO: place holder icon for missing account icons?
                 Log.w(TAG, "No icon resource for account type " + accountType);
             }
         }
-        return icon;
+        if (icon != null) {
+            return icon;
+        } else {
+            return getPackageManager().getDefaultActivityIcon();
+        }
     }
 
     /**
diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java
index 31f7af4..294df95 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardBase.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java
@@ -20,8 +20,10 @@
 import android.graphics.Color;
 import android.os.Bundle;
 import android.os.storage.DiskInfo;
+import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.WindowManager;
@@ -63,6 +65,10 @@
         }
 
         setTheme(R.style.SuwThemeMaterial_Light);
+
+        if (mDisk != null) {
+            mStorage.registerListener(mStorageListener);
+        }
     }
 
     @Override
@@ -82,6 +88,12 @@
         getBackButton().setVisibility(View.GONE);
     }
 
+    @Override
+    protected void onDestroy() {
+        mStorage.unregisterListener(mStorageListener);
+        super.onDestroy();
+    }
+
     protected NavigationBar getNavigationBar() {
         return (NavigationBar) findViewById(R.id.suw_layout_navigation_bar);
     }
@@ -142,4 +154,14 @@
         }
         return null;
     }
+
+    private final StorageEventListener mStorageListener = new StorageEventListener() {
+        @Override
+        public void onDiskDestroyed(DiskInfo disk) {
+            // We know mDisk != null.
+            if (mDisk.id.equals(disk.id)) {
+                finish();
+            }
+        }
+    };
 }
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
index 33f2173..874dc2c 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
@@ -32,10 +32,12 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (mDisk == null) {
+            finish();
+            return;
+        }
         setContentView(R.layout.storage_wizard_generic);
 
-        Preconditions.checkNotNull(mDisk);
-
         mFormatPrivate = getIntent().getBooleanExtra(EXTRA_FORMAT_PRIVATE, false);
 
         if (mFormatPrivate) {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index f1f4510..df2adfd 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -44,10 +44,12 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (mDisk == null) {
+            finish();
+            return;
+        }
         setContentView(R.layout.storage_wizard_progress);
 
-        Preconditions.checkNotNull(mDisk);
-
         mFormatPrivate = getIntent().getBooleanExtra(
                 StorageWizardFormatConfirm.EXTRA_FORMAT_PRIVATE, false);
 
diff --git a/src/com/android/settings/deviceinfo/StorageWizardInit.java b/src/com/android/settings/deviceinfo/StorageWizardInit.java
index 22a8008..61dfaaf 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardInit.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardInit.java
@@ -34,10 +34,12 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (mDisk == null) {
+            finish();
+            return;
+        }
         setContentView(R.layout.storage_wizard_init);
 
-        Preconditions.checkNotNull(mDisk);
-
         setHeaderText(R.string.storage_wizard_init_title, mDisk.getDescription());
 
         mRadioExternal = (RadioButton) findViewById(R.id.storage_wizard_init_external_title);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrate.java b/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
index 7831a07..574408d 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
@@ -35,10 +35,12 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (mDisk == null) {
+            finish();
+            return;
+        }
         setContentView(R.layout.storage_wizard_migrate);
 
-        Preconditions.checkNotNull(mDisk);
-
         setHeaderText(R.string.storage_wizard_migrate_title, mDisk.getDescription());
         setBodyText(R.string.memory_calculating_size);
 
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
index daa76d7..ff74ea2 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
@@ -36,6 +36,11 @@
             mVolume = findFirstVolume(VolumeInfo.TYPE_PRIVATE);
         }
 
+        if (mVolume == null) {
+            finish();
+            return;
+        }
+
         final VolumeInfo sourceVol = getPackageManager().getPrimaryStorageCurrentVolume();
         final String sourceDescrip = mStorage.getBestVolumeDescription(sourceVol);
         final String targetDescrip = mStorage.getBestVolumeDescription(mVolume);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
index 70d93f8..4446c51 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
@@ -39,10 +39,12 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (mVolume == null) {
+            finish();
+            return;
+        }
         setContentView(R.layout.storage_wizard_progress);
 
-        Preconditions.checkNotNull(mVolume);
-
         mMoveId = getIntent().getIntExtra(EXTRA_MOVE_ID, -1);
 
         final String descrip = mStorage.getBestVolumeDescription(mVolume);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java
index 3a802a3..429b03c 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java
@@ -36,6 +36,10 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (mVolume == null) {
+            finish();
+            return;
+        }
         setContentView(R.layout.storage_wizard_generic);
 
         try {
@@ -45,9 +49,6 @@
             throw new RuntimeException(e);
         }
 
-        Preconditions.checkNotNull(mVolume);
-        Preconditions.checkNotNull(mApp);
-
         // Sanity check that target volume is candidate
         Preconditions.checkState(
                 getPackageManager().getPackageCandidateVolumes(mApp).contains(mVolume));
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
index 86e623f..660f85c 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
@@ -36,6 +36,10 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (mVolume == null) {
+            finish();
+            return;
+        }
         setContentView(R.layout.storage_wizard_progress);
 
         mMoveId = getIntent().getIntExtra(EXTRA_MOVE_ID, -1);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardReady.java b/src/com/android/settings/deviceinfo/StorageWizardReady.java
index 6d8846b..d6ea5e4 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardReady.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardReady.java
@@ -26,10 +26,12 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        if (mDisk == null) {
+            finish();
+            return;
+        }
         setContentView(R.layout.storage_wizard_generic);
 
-        Preconditions.checkNotNull(mDisk);
-
         setHeaderText(R.string.storage_wizard_ready_title, mDisk.getDescription());
 
         // TODO: handle mixed partition cases instead of just guessing based on
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
index b3a5d22..552ed71 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
@@ -73,6 +73,7 @@
             }
         } else if (requestCode == ENROLLING) {
             if (resultCode == RESULT_FINISHED) {
+                setResult(RESULT_FINISHED);
                 finish();
             }
         } else {
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/fingerprint/FingerprintEnrollIntroduction.java
new file mode 100644
index 0000000..a488358
--- /dev/null
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollIntroduction.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.fingerprint;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.settings.HelpUtils;
+import com.android.settings.R;
+
+/**
+ * Onboarding activity for fingerprint enrollment.
+ */
+public class FingerprintEnrollIntroduction extends FingerprintEnrollBase {
+
+    public static final String EXTRA_HAS_PASSWORD = "fp_existing_password";
+    private boolean mHasPassword;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.fingerprint_enroll_introduction);
+        setHeaderText(R.string.security_settings_fingerprint_enroll_introduction_title);
+        findViewById(R.id.cancel_button).setOnClickListener(this);
+        findViewById(R.id.learn_more_button).setOnClickListener(this);
+        mHasPassword = getIntent().getBooleanExtra(EXTRA_HAS_PASSWORD, false);
+    }
+
+    @Override
+    protected void onNextButtonClick() {
+        Intent intent = new Intent();
+        final String clazz;
+        if (!mHasPassword) {
+            // No fingerprints registered, launch into enrollment wizard.
+            clazz = FingerprintEnrollOnboard.class.getName();
+        } else {
+            // Lock thingy is already set up, launch directly into find sensor step from wizard.
+            clazz = FingerprintEnrollFindSensor.class.getName();
+        }
+        intent.setClassName("com.android.settings", clazz);
+        startActivityForResult(intent, 0);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == RESULT_FINISHED) {
+            finish();
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v.getId() == R.id.cancel_button) {
+            finish();
+        }
+        if (v.getId() == R.id.learn_more_button) {
+            launchFingerprintHelp();
+        }
+        super.onClick(v);
+    }
+
+    private void launchFingerprintHelp() {
+        Intent helpIntent = HelpUtils.getHelpIntent(this,
+                getString(R.string.help_url_fingerprint), getClass().getName());
+        startActivity(helpIntent);
+    }
+}
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollOnboard.java b/src/com/android/settings/fingerprint/FingerprintEnrollOnboard.java
index f9ad2ba..b78636a 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollOnboard.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollOnboard.java
@@ -49,6 +49,7 @@
         if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST && resultCode == RESULT_FINISHED) {
             byte[] token = data.getByteArrayExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
+            setResult(RESULT_FINISHED);
             launchFindSensor(token);
         } else {
             super.onActivityResult(requestCode, resultCode, data);
diff --git a/src/com/android/settings/print/PrintSettingsFragment.java b/src/com/android/settings/print/PrintSettingsFragment.java
index ebd51d5..d737282 100644
--- a/src/com/android/settings/print/PrintSettingsFragment.java
+++ b/src/com/android/settings/print/PrintSettingsFragment.java
@@ -17,6 +17,7 @@
 package com.android.settings.print;
 
 import android.app.LoaderManager.LoaderCallbacks;
+import android.content.ActivityNotFoundException;
 import android.content.AsyncTaskLoader;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -26,6 +27,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -46,13 +48,12 @@
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.Button;
 import android.widget.Spinner;
 import android.widget.TextView;
 
@@ -75,8 +76,8 @@
  * Fragment with the top level print settings.
  */
 public class PrintSettingsFragment extends SettingsPreferenceFragment
-        implements DialogCreatable, Indexable, OnItemSelectedListener {
-
+        implements DialogCreatable, Indexable, OnItemSelectedListener, OnClickListener {
+    public static final String TAG = "PrintSettingsFragment";
     private static final int LOADER_ID_PRINT_JOBS_LOADER = 1;
 
     private static final String PRINT_JOBS_CATEGORY = "print_jobs_category";
@@ -99,6 +100,8 @@
     private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
             "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
 
+    private static final int ORDER_LAST = 1000;
+
     private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
 
     private final Handler mHandler = new Handler() {
@@ -122,6 +125,7 @@
     private PrintJobsController mPrintJobsController;
     private UserAdapter mProfileSpinnerAdapter;
     private Spinner mSpinner;
+    private Button mAddNewServiceButton;
 
     @Override
     protected int getMetricsCategory() {
@@ -167,18 +171,6 @@
     }
 
     @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        super.onCreateOptionsMenu(menu, inflater);
-        String searchUri = Settings.Secure.getString(getContentResolver(),
-                Settings.Secure.PRINT_SERVICE_SEARCH_URI);
-        if (!TextUtils.isEmpty(searchUri)) {
-            MenuItem menuItem = menu.add(R.string.print_menu_item_add_service);
-            menuItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_NEVER);
-            menuItem.setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)));
-        }
-    }
-
-    @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         ViewGroup contentRoot = (ViewGroup) getListView().getParent();
@@ -186,6 +178,15 @@
                 R.layout.empty_print_state, contentRoot, false);
         TextView textView = (TextView) emptyView.findViewById(R.id.message);
         textView.setText(R.string.print_no_services_installed);
+
+        final Intent addNewServiceIntent = createAddNewServiceIntentOrNull();
+        if (addNewServiceIntent != null) {
+            mAddNewServiceButton = (Button) emptyView.findViewById(R.id.add_new_service);
+            mAddNewServiceButton.setOnClickListener(this);
+            // The empty is used elsewhere too so it's hidden by default.
+            mAddNewServiceButton.setVisibility(View.VISIBLE);
+        }
+
         contentRoot.addView(emptyView);
         getListView().setEmptyView(emptyView);
 
@@ -210,7 +211,9 @@
         List<ComponentName> enabledServices = PrintSettingsUtils
                 .readEnabledPrintServices(getActivity());
 
-        List<ResolveInfo> installedServices = getActivity().getPackageManager()
+        final PackageManager pm = getActivity().getPackageManager();
+
+        List<ResolveInfo> installedServices = pm
                 .queryIntentServices(
                         new Intent(android.printservice.PrintService.SERVICE_INTERFACE),
                         PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
@@ -241,6 +244,11 @@
                 preference.setSummary(getString(R.string.print_feature_state_off));
             }
 
+            final Drawable drawable = installedService.loadIcon(pm);
+            if (drawable != null) {
+                preference.setIcon(drawable);
+            }
+
             Bundle extras = preference.getExtras();
             extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
             extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
@@ -281,9 +289,37 @@
 
         if (mPrintServicesCategory.getPreferenceCount() == 0) {
             getPreferenceScreen().removePreference(mPrintServicesCategory);
+        } else {
+            final Preference addNewServicePreference = newAddServicePreferenceOrNull();
+            if (addNewServicePreference != null) {
+                mPrintServicesCategory.addPreference(addNewServicePreference);
+            }
         }
     }
 
+    private Preference newAddServicePreferenceOrNull() {
+        final Intent addNewServiceIntent = createAddNewServiceIntentOrNull();
+        if (addNewServiceIntent == null) {
+            return null;
+        }
+        Preference preference = new Preference(getContext());
+        preference.setTitle(R.string.print_menu_item_add_service);
+        preference.setIcon(R.drawable.ic_menu_add);
+        preference.setOrder(ORDER_LAST);
+        preference.setIntent(addNewServiceIntent);
+        preference.setPersistent(false);
+        return preference;
+    }
+
+    private Intent createAddNewServiceIntentOrNull() {
+        final String searchUri = Settings.Secure.getString(getContentResolver(),
+                Settings.Secure.PRINT_SERVICE_SEARCH_URI);
+        if (TextUtils.isEmpty(searchUri)) {
+            return null;
+        }
+        return new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri));
+    }
+
     private void startSubSettingsIfNeeded() {
         if (getArguments() == null) {
             return;
@@ -316,6 +352,20 @@
         // Nothing to do
     }
 
+    @Override
+    public void onClick(View v) {
+        if (mAddNewServiceButton == v) {
+            final Intent addNewServiceIntent = createAddNewServiceIntentOrNull();
+            if (addNewServiceIntent != null) { // check again just in case.
+                try {
+                    startActivity(addNewServiceIntent);
+                } catch (ActivityNotFoundException e) {
+                    Log.w(TAG, "Unable to start activity", e);
+                }
+            }
+        }
+    }
+
     private class SettingsPackageMonitor extends PackageMonitor {
         @Override
         public void onPackageAdded(String packageName, int uid) {