Merge "Fix animation video render issue when Settings->Moves is resumed from screen off." into nyc-mr1-dev
diff --git a/res/layout-land/fingerprint_enroll_enrolling.xml b/res/layout-land/fingerprint_enroll_enrolling.xml
index 8154d0c..ba0f803 100644
--- a/res/layout-land/fingerprint_enroll_enrolling.xml
+++ b/res/layout-land/fingerprint_enroll_enrolling.xml
@@ -20,6 +20,7 @@
     android:id="@+id/setup_wizard_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:layout="@layout/suw_glif_blank_template"
     style="?attr/fingerprint_layout_theme">
 
     <LinearLayout
@@ -33,39 +34,62 @@
 
         <!-- Both texts are kept as separate text views so it doesn't jump around in portrait.
              See layouts/fingerprint_enroll_enrolling_base.xml. -->
-        <RelativeLayout
+        <LinearLayout
             android:layout_width="0dp"
             android:layout_weight="1"
-            android:layout_height="wrap_content">
+            android:layout_height="match_parent"
+            android:layout_marginStart="?attr/suwMarginSides"
+            android:layout_marginBottom="@dimen/suw_content_frame_padding_bottom"
+            android:orientation="vertical">
+
+            <ImageView
+                android:id="@+id/suw_layout_icon"
+                style="@style/SuwGlifIcon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="0dp"
+                android:layout_marginEnd="0dp"
+                android:src="@drawable/ic_lock" />
 
             <TextView
-                style="@style/TextAppearance.FingerprintMessage"
-                android:id="@+id/start_message"
+                android:id="@+id/suw_layout_title"
+                style="@style/SuwGlifHeaderTitle"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_alignParentTop="true"
-                android:text="@string/security_settings_fingerprint_enroll_start_message"/>
+                android:layout_marginStart="0dp"
+                android:layout_marginEnd="0dp" />
 
-            <TextView
-                style="@style/TextAppearance.FingerprintMessage"
-                android:id="@+id/repeat_message"
+            <FrameLayout
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_alignParentTop="true"
-                android:text="@string/security_settings_fingerprint_enroll_repeat_message"
-                android:visibility="invisible"/>
+                android:layout_height="wrap_content">
+
+                <TextView
+                    style="@style/TextAppearance.FingerprintMessage"
+                    android:id="@+id/start_message"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/security_settings_fingerprint_enroll_start_message"/>
+
+                <TextView
+                    style="@style/TextAppearance.FingerprintMessage"
+                    android:id="@+id/repeat_message"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/security_settings_fingerprint_enroll_repeat_message"
+                    android:visibility="invisible"/>
+
+            </FrameLayout>
 
             <Button
                 android:id="@+id/skip_button"
                 style="@style/SetupWizardButton.Negative"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_alignParentBottom="true"
-                android:layout_marginBottom="8dp"
+                android:layout_marginTop="8dp"
                 android:text="@string/skip_label"
                 android:visibility="gone" />
 
-        </RelativeLayout>
+        </LinearLayout>
 
         <FrameLayout
             android:layout_width="0dp"
@@ -84,6 +108,7 @@
                 android:layout_height="wrap_content"
                 android:layout_marginBottom="16dp"
                 android:layout_gravity="center_horizontal|bottom"
+                android:accessibilityLiveRegion="polite"
                 android:visibility="invisible"/>
 
         </FrameLayout>
diff --git a/res/layout/dashboard.xml b/res/layout/dashboard.xml
index f1bf259..73a7255 100644
--- a/res/layout/dashboard.xml
+++ b/res/layout/dashboard.xml
@@ -25,4 +25,5 @@
     android:paddingStart="@dimen/dashboard_padding_start"
     android:paddingEnd="@dimen/dashboard_padding_end"
     android:paddingTop="@dimen/dashboard_padding_top"
-    android:paddingBottom="@dimen/dashboard_padding_bottom"/>
+    android:paddingBottom="@dimen/dashboard_padding_bottom"
+    android:scrollbars="vertical"/>
diff --git a/res/layout/support_offline_escalation_options.xml b/res/layout/support_offline_escalation_options.xml
index 08c52aa..18d8f98 100644
--- a/res/layout/support_offline_escalation_options.xml
+++ b/res/layout/support_offline_escalation_options.xml
@@ -59,7 +59,8 @@
         style="@style/SupportPrimaryButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_margin="8dp"/>
+        android:layout_margin="8dp"
+        android:layoutDirection="ltr"/>
     <Button
         android:id="@android:id/text2"
         style="@style/SupportSecondaryButton"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9b8614a..cc3ee44 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -833,11 +833,6 @@
     <!-- Text shown in fingerprint enroll when we didn't observe progress for a few seconds. [CHAR LIMIT=100] -->
     <string name="security_settings_fingerprint_enroll_lift_touch_again">Lift finger, then touch sensor again</string>
 
-    <!-- Message shown in fingerprint enrollment during setup wizard once enrollment is complete. [CHAR LIMIT=NONE] -->
-    <string name="setup_fingerprint_enroll_finish_message">Whenever you see this icon, you can use your fingerprint.</string>
-    <!-- Secondary message shown in fingerprint enrollment during setup wizard once enrollment is complete, telling the user how to change the settings after they are done with setup. [CHAR LIMIT=NONE] -->
-    <string name="setup_fingerprint_enroll_finish_secondary_message">To change your settings, go to Settings &gt; Security &gt; Fingerprint.</string>
-
     <!-- Text shown when "Add fingerprint" button is disabled -->
     <string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
 
diff --git a/res/values/themes.xml b/res/values/themes.xml
index e861113..0009bed 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -99,6 +99,7 @@
         <item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
         <item name="@android:preferenceFragmentStyle">@style/PreferenceFragmentStyle</item>
         <item name="apnPreferenceStyle">@style/ApnPreference</item>
+        <item name="android:scrollbars">vertical</item>
     </style>
 
     <style name="PreferenceTheme.SetupWizard" parent="SetupWizardTheme">
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index 4e5da6e..08eae1a 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -1035,7 +1035,7 @@
 
     private void updateOemUnlockOptions() {
         if (mEnableOemUnlock != null) {
-            updateSwitchPreference(mEnableOemUnlock, isBootloaderUnlocked());
+            updateSwitchPreference(mEnableOemUnlock, Utils.isOemUnlockEnabled(getActivity()));
             updateOemUnlockSettingDescription();
             // Showing mEnableOemUnlock preference as device has persistent data block.
             mEnableOemUnlock.setDisabledByAdmin(null);
diff --git a/src/com/android/settings/accounts/AccountSyncSettings.java b/src/com/android/settings/accounts/AccountSyncSettings.java
index fc760e6..8ceb5e5 100644
--- a/src/com/android/settings/accounts/AccountSyncSettings.java
+++ b/src/com/android/settings/accounts/AccountSyncSettings.java
@@ -28,9 +28,12 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentSender;
 import android.content.SyncAdapterType;
 import android.content.SyncInfo;
 import android.content.SyncStatusInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
 import android.content.pm.UserInfo;
 import android.os.Binder;
@@ -58,7 +61,6 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -73,6 +75,7 @@
     private static final int REALLY_REMOVE_DIALOG = 100;
     private static final int FAILED_REMOVAL_DIALOG = 101;
     private static final int CANT_DO_ONETIME_SYNC_DIALOG = 102;
+
     private TextView mUserId;
     private TextView mProviderId;
     private ImageView mProviderIcon;
@@ -234,13 +237,15 @@
         mAuthenticatorHelper.stopListeningToAccountUpdates();
     }
 
-    private void addSyncStateSwitch(Account account, String authority) {
+    private void addSyncStateSwitch(Account account, String authority,
+            String packageName, int uid) {
         SyncStateSwitchPreference item = (SyncStateSwitchPreference) getCachedPreference(authority);
         if (item == null) {
-            item = new SyncStateSwitchPreference(getPrefContext(), account, authority);
+            item = new SyncStateSwitchPreference(getPrefContext(), account, authority,
+                    packageName, uid);
             getPreferenceScreen().addPreference(item);
         } else {
-            item.setup(account, authority);
+            item.setup(account, authority, packageName, uid);
         }
         item.setPersistent(false);
         final ProviderInfo providerInfo = getPackageManager().resolveContentProviderAsUser(
@@ -323,20 +328,56 @@
     }
 
     @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == Activity.RESULT_OK) {
+            final int uid = requestCode;
+            final int count = getPreferenceScreen().getPreferenceCount();
+            for (int i = 0; i < count; i++) {
+                Preference preference = getPreferenceScreen().getPreference(i);
+                if (preference instanceof SyncStateSwitchPreference) {
+                    SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
+                    if (syncPref.getUid() == uid) {
+                        onPreferenceTreeClick(syncPref);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
     public boolean onPreferenceTreeClick(Preference preference) {
+        if (getActivity() == null) {
+            return false;
+        }
         if (preference instanceof SyncStateSwitchPreference) {
             SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
             String authority = syncPref.getAuthority();
             Account account = syncPref.getAccount();
             final int userId = mUserHandle.getIdentifier();
+            String packageName = syncPref.getPackageName();
+
             boolean syncAutomatically = ContentResolver.getSyncAutomaticallyAsUser(account,
                     authority, userId);
             if (syncPref.isOneTimeSyncMode()) {
+                // If the sync adapter doesn't have access to the account we either
+                // request access by starting an activity if possible or kick off the
+                // sync which will end up posting an access request notification.
+                if (requestAccountAccessIfNeeded(packageName)) {
+                    return true;
+                }
                 requestOrCancelSync(account, authority, true);
             } else {
                 boolean syncOn = syncPref.isChecked();
                 boolean oldSyncState = syncAutomatically;
                 if (syncOn != oldSyncState) {
+                    // Toggling this switch triggers sync but we may need a user approval.
+                    // If the sync adapter doesn't have access to the account we either
+                    // request access by starting an activity if possible or kick off the
+                    // sync which will end up posting an access request notification.
+                    if (syncOn && requestAccountAccessIfNeeded(packageName)) {
+                        return true;
+                    }
                     // if we're enabling sync, this will request a sync as well
                     ContentResolver.setSyncAutomaticallyAsUser(account, authority, syncOn, userId);
                     // if the master sync switch is off, the request above will
@@ -353,6 +394,36 @@
         }
     }
 
+    private boolean requestAccountAccessIfNeeded(String packageName) {
+        if (packageName == null) {
+            return false;
+        }
+
+        final int uid;
+        try {
+            uid = getContext().getPackageManager().getPackageUidAsUser(
+                    packageName, mUserHandle.getIdentifier());
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "Invalid sync ", e);
+            return false;
+        }
+
+        AccountManager accountManager = getContext().getSystemService(AccountManager.class);
+        if (!accountManager.hasAccountAccess(mAccount, packageName, mUserHandle)) {
+            IntentSender intent = accountManager.createRequestAccountAccessIntentSenderAsUser(
+                    mAccount, packageName, mUserHandle);
+            if (intent != null) {
+                try {
+                    startIntentSenderForResult(intent, uid, null, 0, 0, 0, null);
+                    return true;
+                } catch (IntentSender.SendIntentException e) {
+                    Log.e(TAG, "Error requesting account access", e);
+                }
+            }
+        }
+        return false;
+    }
+
     private void startSyncForEnabledProviders() {
         requestOrCancelSyncForEnabledProviders(true /* start them */);
         final Activity activity = getActivity();
@@ -520,7 +591,7 @@
 
         SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
                 mUserHandle.getIdentifier());
-        ArrayList<String> authorities = new ArrayList<String>();
+        ArrayList<SyncAdapterType> authorities = new ArrayList<>();
         for (int i = 0, n = syncAdapters.length; i < n; i++) {
             final SyncAdapterType sa = syncAdapters[i];
             // Only keep track of sync adapters for this account
@@ -530,7 +601,7 @@
                     Log.d(TAG, "updateAccountSwitches: added authority " + sa.authority
                             + " to accountType " + sa.accountType);
                 }
-                authorities.add(sa.authority);
+                authorities.add(sa);
             } else {
                 // keep track of invisible sync adapters, so sync now forces
                 // them to sync as well.
@@ -543,15 +614,23 @@
         }
         cacheRemoveAllPrefs(getPreferenceScreen());
         for (int j = 0, m = authorities.size(); j < m; j++) {
-            final String authority = authorities.get(j);
+            final SyncAdapterType syncAdapter = authorities.get(j);
             // We could check services here....
-            int syncState = ContentResolver.getIsSyncableAsUser(mAccount, authority,
+            int syncState = ContentResolver.getIsSyncableAsUser(mAccount, syncAdapter.authority,
                     mUserHandle.getIdentifier());
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.d(TAG, "  found authority " + authority + " " + syncState);
+                Log.d(TAG, "  found authority " + syncAdapter.authority + " " + syncState);
             }
             if (syncState > 0) {
-                addSyncStateSwitch(mAccount, authority);
+                final int uid;
+                try {
+                    uid = getContext().getPackageManager().getPackageUidAsUser(
+                            syncAdapter.getPackageName(), mUserHandle.getIdentifier());
+                    addSyncStateSwitch(mAccount, syncAdapter.authority,
+                            syncAdapter.getPackageName(), uid);
+                } catch (PackageManager.NameNotFoundException e) {
+                    Log.e(TAG, "No uid for package" + syncAdapter.getPackageName(), e);
+                }
             }
         }
         removeCachedPrefs(getPreferenceScreen());
diff --git a/src/com/android/settings/accounts/SyncStateSwitchPreference.java b/src/com/android/settings/accounts/SyncStateSwitchPreference.java
index c6632d0..058fedd 100644
--- a/src/com/android/settings/accounts/SyncStateSwitchPreference.java
+++ b/src/com/android/settings/accounts/SyncStateSwitchPreference.java
@@ -36,6 +36,8 @@
     private boolean mFailed = false;
     private Account mAccount;
     private String mAuthority;
+    private String mPackageName;
+    private int mUid;
 
     /**
      * A mode for this preference where clicking does a one-time sync instead of
@@ -47,16 +49,21 @@
         super(context, attrs, 0, R.style.SyncSwitchPreference);
         mAccount = null;
         mAuthority = null;
+        mPackageName = null;
+        mUid = 0;
     }
 
-    public SyncStateSwitchPreference(Context context, Account account, String authority) {
+    public SyncStateSwitchPreference(Context context, Account account, String authority,
+            String packageName, int uid) {
         super(context, null, 0, R.style.SyncSwitchPreference);
-        setup(account, authority);
+        setup(account, authority, packageName, uid);
     }
 
-    public void setup(Account account, String authority) {
+    public void setup(Account account, String authority, String packageName, int uid) {
         mAccount = account;
         mAuthority = authority;
+        mPackageName = packageName;
+        mUid = uid;
         notifyChanged();
     }
 
@@ -152,4 +159,12 @@
     public String getAuthority() {
         return mAuthority;
     }
+
+    public String getPackageName() {
+        return mPackageName;
+    };
+
+    public int getUid() {
+        return mUid;
+    };
 }
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 1c7e22d..12f036a 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -42,6 +42,7 @@
 import com.android.settingslib.drawer.SettingsDrawerActivity;
 import com.android.settingslib.drawer.Tile;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class DashboardSummary extends InstrumentedFragment
@@ -63,6 +64,8 @@
     private static final String SUGGESTIONS = "suggestions";
 
     private static final String EXTRA_SCROLL_POSITION = "scroll_position";
+    private static final String EXTRA_SUGGESTION_SHOWN_LOGGED = "suggestions_shown_logged";
+    private static final String EXTRA_SUGGESTION_HIDDEN_LOGGED = "suggestions_hidden_logged";
 
     private FocusRecyclerView mDashboard;
     private DashboardAdapter mAdapter;
@@ -71,6 +74,8 @@
     private SuggestionParser mSuggestionParser;
     private LinearLayoutManager mLayoutManager;
     private SuggestionsChecks mSuggestionsChecks;
+    private ArrayList<String> mSuggestionsShownLogged;
+    private ArrayList<String> mSuggestionsHiddenLogged;
 
     @Override
     protected int getMetricsCategory() {
@@ -90,6 +95,15 @@
         mSuggestionParser = new SuggestionParser(context,
                 context.getSharedPreferences(SUGGESTIONS, 0), R.xml.suggestion_ordering);
         mSuggestionsChecks = new SuggestionsChecks(getContext());
+        if (savedInstanceState == null) {
+            mSuggestionsShownLogged = new ArrayList<>();
+            mSuggestionsHiddenLogged = new ArrayList<>();
+        } else {
+            mSuggestionsShownLogged =
+                    savedInstanceState.getStringArrayList(EXTRA_SUGGESTION_SHOWN_LOGGED);
+            mSuggestionsHiddenLogged =
+                    savedInstanceState.getStringArrayList(EXTRA_SUGGESTION_HIDDEN_LOGGED);
+        }
         if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
                 + " ms");
     }
@@ -112,12 +126,6 @@
                 MetricsLogger.visible(getContext(), c.getMetricsConstant());
             }
         }
-        if (mAdapter.getSuggestions() != null) {
-            for (Tile suggestion : mAdapter.getSuggestions()) {
-                MetricsLogger.action(getContext(), MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
-                        DashboardAdapter.getSuggestionIdentifier(getContext(), suggestion));
-            }
-        }
         if (DEBUG_TIMING) Log.d(TAG, "onStart took " + (System.currentTimeMillis() - startTime)
                 + " ms");
     }
@@ -136,9 +144,15 @@
         if (mAdapter.getSuggestions() == null) {
             return;
         }
-        for (Tile suggestion : mAdapter.getSuggestions()) {
-            MetricsLogger.action(getContext(), MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION,
-                    DashboardAdapter.getSuggestionIdentifier(getContext(), suggestion));
+        if (!getActivity().isChangingConfigurations()) {
+            for (Tile suggestion : mAdapter.getSuggestions()) {
+                String id = DashboardAdapter.getSuggestionIdentifier(getContext(), suggestion);
+                if (!mSuggestionsHiddenLogged.contains(id)) {
+                    mSuggestionsHiddenLogged.add(id);
+                    MetricsLogger.action(getContext(),
+                            MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, id);
+                }
+            }
         }
     }
 
@@ -169,6 +183,8 @@
         if (mAdapter != null) {
             mAdapter.onSaveInstanceState(outState);
         }
+        outState.putStringArrayList(EXTRA_SUGGESTION_HIDDEN_LOGGED, mSuggestionsHiddenLogged);
+        outState.putStringArrayList(EXTRA_SUGGESTION_SHOWN_LOGGED, mSuggestionsShownLogged);
     }
 
     @Override
@@ -222,9 +238,17 @@
         protected List<Tile> doInBackground(Void... params) {
             List<Tile> suggestions = mSuggestionParser.getSuggestions();
             for (int i = 0; i < suggestions.size(); i++) {
-                if (mSuggestionsChecks.isSuggestionComplete(suggestions.get(i))) {
-                    mAdapter.disableSuggestion(suggestions.get(i));
+                Tile suggestion = suggestions.get(i);
+                if (mSuggestionsChecks.isSuggestionComplete(suggestion)) {
+                    mAdapter.disableSuggestion(suggestion);
                     suggestions.remove(i--);
+                } else {
+                    String id = DashboardAdapter.getSuggestionIdentifier(getContext(), suggestion);
+                    if (!mSuggestionsShownLogged.contains(id)) {
+                        mSuggestionsShownLogged.add(id);
+                        MetricsLogger.action(getContext(),
+                                MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, id);
+                    }
                 }
             }
             return suggestions;
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index d943e52..4e0d8fa 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -224,6 +224,7 @@
             mMePreference.setSummary(R.string.user_admin);
         }
         mAddUser = (DimmableIconPreference) findPreference(KEY_ADD_USER);
+        mAddUser.useAdminDisabledSummary(false);
         // Determine if add user/profile button should be visible
         if (mUserCaps.mCanAddUser && Utils.isDeviceProvisioned(getActivity())) {
             mAddUser.setOnPreferenceClickListener(this);