Merge "Fix preview screen crashing and glitches for Display / Font size Bug: 28223545 Bug: 28223533 Bug: 28210654 Bug: 28210242 Bug: 28208955 Bug: 27699996" into nyc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index eca1cb4..d9ee179 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1557,6 +1557,7 @@
         <activity android:name="ConfirmDeviceCredentialActivity$InternalActivity"
             android:exported="false"
             android:permission="android.permission.MANAGE_USERS"
+            android:resizeableActivity="false"
             android:theme="@android:style/Theme.NoDisplay">
             <intent-filter android:priority="1">
                 <action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER" />
diff --git a/res/layout/condition_card.xml b/res/layout/condition_card.xml
index 0e480a5..c1224b5 100644
--- a/res/layout/condition_card.xml
+++ b/res/layout/condition_card.xml
@@ -85,11 +85,13 @@
 
             <!-- TODO: Better background -->
             <View
+                android:id="@+id/divider"
                 android:layout_width="match_parent"
                 android:layout_height=".25dp"
                 android:background="@android:color/white" />
 
             <com.android.internal.widget.ButtonBarLayout
+                android:id="@+id/buttonBar"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:paddingTop="8dp"
diff --git a/res/layout/fingerprint_enroll_finish_base.xml b/res/layout/fingerprint_enroll_finish_base.xml
index 03447b3..15ee22a 100644
--- a/res/layout/fingerprint_enroll_finish_base.xml
+++ b/res/layout/fingerprint_enroll_finish_base.xml
@@ -49,20 +49,25 @@
             android:visibility="gone" />
 
         <View
-            android:layout_height="0dp"
+            android:layout_height="24dp"
             android:layout_width="match_parent"
             android:layout_weight="1"/>
 
         <ImageView
             android:id="@+id/fingerprint_in_app_indicator"
-            android:layout_width="@dimen/fingerprint_in_app_indicator_size"
-            android:layout_height="@dimen/fingerprint_in_app_indicator_size"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_weight="5"
+            android:minHeight="@dimen/fingerprint_in_app_indicator_min_size"
+            android:minWidth="@dimen/fingerprint_in_app_indicator_min_size"
+            android:maxHeight="@dimen/fingerprint_in_app_indicator_max_size"
+            android:maxWidth="@dimen/fingerprint_in_app_indicator_max_size"
             android:layout_gravity="center_horizontal"
             android:contentDescription="@android:string/fingerprint_icon_content_description"
             android:src="@drawable/fp_app_indicator" />
 
         <View
-            android:layout_height="0dp"
+            android:layout_height="24dp"
             android:layout_width="match_parent"
             android:layout_weight="1"/>
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c904f2d..ef7efa2 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -228,7 +228,9 @@
     <dimen name="fingerprint_animation_size">88dp</dimen>
     <dimen name="fingerprint_progress_bar_size">192dp</dimen>
     <dimen name="fingerprint_enrolling_content_margin_top">36dp</dimen>
-    <dimen name="fingerprint_in_app_indicator_size">120dp</dimen>
+    <dimen name="fingerprint_in_app_indicator_size">124dp</dimen>
+    <dimen name="fingerprint_in_app_indicator_min_size">124dp</dimen>
+    <dimen name="fingerprint_in_app_indicator_max_size">264dp</dimen>
 
     <dimen name="setup_fingerprint_ring_radius">80dip</dimen>
     <dimen name="setup_fingerprint_progress_bar_size">168dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 16ab708..3eb6d3d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7243,6 +7243,9 @@
     <!-- Button that leads to list of apps with unrestricted data access [CHAR LIMIT=60] -->
     <string name="unrestricted_data_saver">Unrestricted data access</string>
 
+    <!-- Description of message shown when app is blacklisted for background data access [CHAR LIMIT=NONE] -->
+    <string name="restrict_background_blacklisted">Background data is turned off</string>
+
     <!-- Summary for the Data Saver feature being on [CHAR LIMIT=NONE] -->
     <string name="data_saver_on">On</string>
 
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index 05ed6e7..ab57649 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -47,6 +47,11 @@
             android:title="@string/tts_reset_speech_rate_title"
             android:summary="@string/tts_reset_speech_rate_summary" />
 
+        <Preference android:key="reset_speech_pitch"
+            android:persistent="false"
+            android:title="@string/tts_reset_speech_pitch_title"
+            android:summary="@string/tts_reset_speech_pitch_summary" />
+
         <Preference android:key="tts_play_example"
             android:persistent="false"
             android:title="@string/tts_play_example_title"
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 46a3d9b..e439bed 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -347,11 +347,12 @@
         // If there's no profile photo, assign a default avatar
         if (avatarDataStream == null) {
             assignDefaultPhoto(context, userId);
-        } else {
-            UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-            Bitmap icon = BitmapFactory.decodeStream(avatarDataStream);
-            um.setUserIcon(userId, icon);
+            return;
         }
+
+        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        Bitmap icon = BitmapFactory.decodeStream(avatarDataStream);
+        um.setUserIcon(userId, icon);
         try {
             avatarDataStream.close();
         } catch (IOException ioe) { }
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 7813745..14277c9 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -52,7 +52,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.Preference.OnPreferenceClickListener;
@@ -73,6 +72,7 @@
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
+
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
@@ -81,6 +81,7 @@
 import com.android.settings.DeviceAdminAdd;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
 import com.android.settings.applications.PermissionsSummaryHelper.PermissionsResultCallback;
 import com.android.settings.datausage.AppDataUsage;
@@ -741,14 +742,19 @@
     }
 
     private void startAppInfoFragment(Class<?> fragment, CharSequence title) {
+        startAppInfoFragment(fragment, title, this, mAppEntry);
+    }
+
+    public static void startAppInfoFragment(Class<?> fragment, CharSequence title,
+            SettingsPreferenceFragment caller, AppEntry appEntry) {
         // start new fragment to display extended information
         Bundle args = new Bundle();
-        args.putString(ARG_PACKAGE_NAME, mAppEntry.info.packageName);
-        args.putInt(ARG_PACKAGE_UID, mAppEntry.info.uid);
+        args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
+        args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
         args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
 
-        SettingsActivity sa = (SettingsActivity) getActivity();
-        sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT);
+        SettingsActivity sa = (SettingsActivity) caller.getActivity();
+        sa.startPreferencePanel(fragment.getName(), args, -1, title, caller, SUB_INFO_FRAGMENT);
     }
 
     /*
@@ -929,7 +935,7 @@
     }
 
     private boolean hasPermission(String permission) {
-        if (mPackageInfo.requestedPermissions == null) {
+        if (mPackageInfo == null || mPackageInfo.requestedPermissions == null) {
             return false;
         }
         for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) {
diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java b/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
index a5d0701..9a45a5a 100644
--- a/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
+++ b/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
@@ -74,13 +74,13 @@
         expand.setOnClickListener(onExpandListener);
 
         View detailGroup = view.itemView.findViewById(R.id.detail_group);
+        CharSequence[] actions = condition.getActions();
         if (isExpanded != (detailGroup.getVisibility() == View.VISIBLE)) {
             animateChange(view.itemView, view.itemView.findViewById(R.id.content),
-                    detailGroup, isExpanded);
+                    detailGroup, isExpanded, actions.length > 0);
         }
         if (isExpanded) {
             view.summary.setText(condition.getSummary());
-            CharSequence[] actions = condition.getActions();
             for (int i = 0; i < 2; i++) {
                 Button button = (Button) detailGroup.findViewById(i == 0
                         ? R.id.first_action : R.id.second_action);
@@ -105,7 +105,9 @@
     }
 
     private static void animateChange(final View view, final View content,
-            final View detailGroup, final boolean visible) {
+            final View detailGroup, final boolean visible, final boolean hasButtons) {
+        setViewVisibility(detailGroup, R.id.divider, hasButtons);
+        setViewVisibility(detailGroup, R.id.buttonBar, hasButtons);
         final int beforeBottom = content.getBottom();
         setHeight(detailGroup, visible ? LayoutParams.WRAP_CONTENT : 0);
         detailGroup.setVisibility(View.VISIBLE);
@@ -138,4 +140,11 @@
         params.height = height;
         detailGroup.setLayoutParams(params);
     }
+
+    private static void setViewVisibility(View containerView, int viewId, boolean visible) {
+        View view = containerView.findViewById(viewId);
+        if (view != null) {
+            view.setVisibility(visible ? View.VISIBLE : View.GONE);
+        }
+    }
 }
diff --git a/src/com/android/settings/dashboard/conditional/HotspotCondition.java b/src/com/android/settings/dashboard/conditional/HotspotCondition.java
index be74c9e..17be591 100644
--- a/src/com/android/settings/dashboard/conditional/HotspotCondition.java
+++ b/src/com/android/settings/dashboard/conditional/HotspotCondition.java
@@ -21,10 +21,15 @@
 import android.graphics.drawable.Icon;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.TetherSettings;
 import com.android.settings.Utils;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.TetherUtil;
 
 public class HotspotCondition extends Condition {
@@ -74,7 +79,12 @@
 
     @Override
     public CharSequence[] getActions() {
-        return new CharSequence[] { mManager.getContext().getString(R.string.condition_turn_off) };
+        final Context context = mManager.getContext();
+        if (RestrictedLockUtils.hasBaseUserRestriction(context,
+                UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) {
+            return new CharSequence[0];
+        }
+        return new CharSequence[] { context.getString(R.string.condition_turn_off) };
     }
 
     @Override
@@ -86,8 +96,15 @@
     @Override
     public void onActionClick(int index) {
         if (index == 0) {
-            TetherUtil.setWifiTethering(false, mManager.getContext());
-            setActive(false);
+            final Context context = mManager.getContext();
+            final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(context,
+                    UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId());
+            if (admin != null) {
+                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, admin);
+            } else {
+                TetherUtil.setWifiTethering(false, context);
+                setActive(false);
+            }
         } else {
             throw new IllegalArgumentException("Unexpected index " + index);
         }
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index 3da3bac..037614e 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -216,7 +216,8 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         if (preference == mRestrictBackground) {
-            setAppRestrictBackground(!(Boolean) newValue);
+            mDataSaverBackend.setIsBlacklisted(mAppItem.key, mPackageName, !(Boolean) newValue);
+            updatePrefs();        // TODO: should have been notified by NPMS instead
             return true;
         } else if (preference == mUnrestrictedData) {
             mDataSaverBackend.setIsWhitelisted(mAppItem.key, mPackageName, (Boolean) newValue);
@@ -287,17 +288,6 @@
         return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
     }
 
-    private void setAppRestrictBackground(boolean restrictBackground) {
-        final int uid = mAppItem.key;
-        services.mPolicyManager.setUidPolicy(
-                uid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
-        updatePrefs();        // TODO: should have been notified by NPMS instead
-        if (restrictBackground) {
-            MetricsLogger.action(getContext(),
-                    MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, mPackageName);
-        }
-    }
-
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
diff --git a/src/com/android/settings/datausage/AppStateDataUsageBridge.java b/src/com/android/settings/datausage/AppStateDataUsageBridge.java
index 1aff496..0b535d0 100644
--- a/src/com/android/settings/datausage/AppStateDataUsageBridge.java
+++ b/src/com/android/settings/datausage/AppStateDataUsageBridge.java
@@ -37,20 +37,24 @@
         final int N = apps.size();
         for (int i = 0; i < N; i++) {
             AppEntry app = apps.get(i);
-            app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(app.info.uid));
+            app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(app.info.uid),
+                    mDataSaverBackend.isBlacklisted(app.info.uid));
         }
     }
 
     @Override
     protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
-        app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(uid));
+        app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(uid),
+                mDataSaverBackend.isBlacklisted(uid));
     }
 
     public static class DataUsageState {
         public boolean isDataSaverWhitelisted;
+        public boolean isDataSaverBlacklisted;
 
-        public DataUsageState(boolean isDataSaverWhitelisted) {
+        public DataUsageState(boolean isDataSaverWhitelisted, boolean isDataSaverBlacklisted) {
             this.isDataSaverWhitelisted = isDataSaverWhitelisted;
+            this.isDataSaverBlacklisted = isDataSaverBlacklisted;
         }
     }
 }
diff --git a/src/com/android/settings/datausage/DataSaverBackend.java b/src/com/android/settings/datausage/DataSaverBackend.java
index d72fe3d..55521a8 100644
--- a/src/com/android/settings/datausage/DataSaverBackend.java
+++ b/src/com/android/settings/datausage/DataSaverBackend.java
@@ -29,6 +29,9 @@
 
 import java.util.ArrayList;
 
+import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+
 public class DataSaverBackend {
 
     private static final String TAG = "DataSaverBackend";
@@ -40,6 +43,7 @@
     private final INetworkPolicyManager mIPolicyManager;
     private final ArrayList<Listener> mListeners = new ArrayList<>();
     private SparseBooleanArray mWhitelist;
+    private SparseBooleanArray mBlacklist;
 
     // TODO: Staticize into only one.
     public DataSaverBackend(Context context) {
@@ -121,6 +125,35 @@
         }
     }
 
+    public void refreshBlacklist() {
+        loadBlacklist();
+    }
+
+    public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) {
+        mPolicyManager.setUidPolicy(
+                uid, blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
+        if (blacklisted) {
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, packageName);
+        }
+    }
+
+    public boolean isBlacklisted(int uid) {
+        if (mBlacklist == null) {
+            loadBlacklist();
+        }
+        return mBlacklist.get(uid);
+    }
+
+    private void loadBlacklist() {
+        mBlacklist = new SparseBooleanArray();
+        try {
+            for (int uid : mIPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
+                mBlacklist.put(uid, true);
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
     private void handleRestrictBackgroundChanged(boolean isDataSaving) {
         for (int i = 0; i < mListeners.size(); i++) {
             mListeners.get(i).onDataSaverChanged(isDataSaving);
@@ -129,7 +162,8 @@
 
     private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
         @Override
-        public void onUidRulesChanged(int i, int i1) throws RemoteException {
+        public void onUidRulesChanged(int uid, int uidRules) throws RemoteException {
+            // TODO: update UI accordingly
         }
 
         @Override
diff --git a/src/com/android/settings/datausage/DataSaverSummary.java b/src/com/android/settings/datausage/DataSaverSummary.java
index e8c8cdd..591f2c5 100644
--- a/src/com/android/settings/datausage/DataSaverSummary.java
+++ b/src/com/android/settings/datausage/DataSaverSummary.java
@@ -70,6 +70,7 @@
     public void onResume() {
         super.onResume();
         mDataSaverBackend.refreshWhitelist();
+        mDataSaverBackend.refreshBlacklist();
         mDataSaverBackend.addListener(this);
         mSession.resume();
         mDataUsageBridge.resume();
diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
index 36ec050..c8df0ba 100644
--- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java
+++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
@@ -24,10 +24,15 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+
 import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settings.AppHeader;
 import com.android.settings.R;
+import com.android.settings.SettingsActivity;
 import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.applications.AppInfoBase;
 import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.applications.InstalledAppDetails;
 import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -40,6 +45,7 @@
 
     private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 42;
     private static final String EXTRA_SHOW_SYSTEM = "show_system";
+
     private ApplicationsState mApplicationsState;
     private AppStateDataUsageBridge mDataUsageBridge;
     private ApplicationsState.Session mSession;
@@ -144,11 +150,11 @@
     }
 
     @Override
-    public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
+    public void onRebuildComplete(ArrayList<AppEntry> apps) {
         cacheRemoveAllPrefs(getPreferenceScreen());
         final int N = apps.size();
         for (int i = 0; i < N; i++) {
-            ApplicationsState.AppEntry entry = apps.get(i);
+            AppEntry entry = apps.get(i);
             String key = entry.info.packageName + "|" + entry.info.uid;
             AccessPreference preference = (AccessPreference) getCachedPreference(key);
             if (preference == null) {
@@ -202,32 +208,60 @@
             boolean whitelisted = newValue == Boolean.TRUE;
             mDataSaverBackend.setIsWhitelisted(accessPreference.mEntry.info.uid,
                     accessPreference.mEntry.info.packageName, whitelisted);
-            ((AppStateDataUsageBridge.DataUsageState) accessPreference.mEntry.extraInfo)
-                    .isDataSaverWhitelisted = whitelisted;
+            accessPreference.mState.isDataSaverWhitelisted = whitelisted;
             return true;
         }
         return false;
     }
 
     private class AccessPreference extends SwitchPreference {
-        private final ApplicationsState.AppEntry mEntry;
+        private final AppEntry mEntry;
+        private final DataUsageState mState;
 
-        public AccessPreference(Context context, ApplicationsState.AppEntry entry) {
+        public AccessPreference(final Context context, AppEntry entry) {
             super(context);
             mEntry = entry;
+            mState = (DataUsageState) mEntry.extraInfo;
             mEntry.ensureLabel(getContext());
-            setTitle(entry.label);
-            final DataUsageState state = (DataUsageState) entry.extraInfo;
-            setChecked(state != null && state.isDataSaverWhitelisted);
+            setState();
             if (mEntry.icon != null) {
                 setIcon(mEntry.icon);
             }
+            setOnPreferenceClickListener( new OnPreferenceClickListener() {
+
+                @Override
+                public boolean onPreferenceClick(Preference pref) {
+                    if (mState.isDataSaverBlacklisted) {
+                        InstalledAppDetails.startAppInfoFragment(AppDataUsage.class,
+                                context.getString(R.string.app_data_usage),
+                                UnrestrictedDataAccess.this,
+                                mEntry);
+                        return false;
+                    }
+                    return true;
+                }});
+        }
+
+        // Sets UI state based on whitelist/blacklist status.
+        private void setState() {
+            setTitle(mEntry.label);
+            // TODO: state is cached, so if blacklist/whitelist changes, it's not updated.
+            // For example, if the initial state is blacklisted, the user taps the preference,
+            // removes the blacklist, and then taps back, the state is not refreshed.
+            // The proper fix for this problem is to implement onUidRulesChanged() on
+            // DataSaverBackend and update the UI accordingly.
+            if (mState != null) {
+                setChecked(mState.isDataSaverWhitelisted);
+                if (mState.isDataSaverBlacklisted) {
+                    setSummary(R.string.restrict_background_blacklisted);
+                }
+                // TODO: might need to reset summary once it listens to onUidRulesChanged()
+            }
         }
 
         public void reuse() {
-            setTitle(mEntry.label);
-            final DataUsageState state = (DataUsageState) mEntry.extraInfo;
-            setChecked(state != null && state.isDataSaverWhitelisted);
+            setState();
+            notifyChanged();
         }
 
         @Override
@@ -244,7 +278,10 @@
                     }
                 });
             }
+            holder.findViewById(android.R.id.widget_frame)
+                    .setVisibility(mState.isDataSaverBlacklisted ? View.INVISIBLE : View.VISIBLE);
             super.onBindViewHolder(holder);
         }
     }
+
 }
diff --git a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
index 1de3fcc..d35f895 100644
--- a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
@@ -16,9 +16,15 @@
 
 package com.android.settings.inputmethod;
 
+import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
@@ -40,8 +46,6 @@
 public final class AvailableVirtualKeyboardFragment extends SettingsPreferenceFragment
         implements InputMethodPreference.OnSavePreferenceListener {
 
-    private static final Drawable NO_ICON = new ColorDrawable(Color.TRANSPARENT);
-
     private final ArrayList<InputMethodPreference> mInputMethodPreferenceList = new ArrayList<>();
     private InputMethodSettingValuesWrapper mInputMethodSettingValues;
     private InputMethodManager mImm;
@@ -85,27 +89,68 @@
         return MetricsEvent.ENABLE_VIRTUAL_KEYBOARDS;
     }
 
+    @Nullable
+    private static Drawable loadDrawable(@NonNull final PackageManager packageManager,
+            @NonNull final String packageName, @DrawableRes final int resId,
+            @NonNull final ApplicationInfo applicationInfo) {
+        if (resId == 0) {
+            return null;
+        }
+        try {
+            return packageManager.getDrawable(packageName, resId, applicationInfo);
+        } catch (Exception e){
+            return null;
+        }
+    }
+
+    @NonNull
+    private static Drawable getInputMethodIcon(@NonNull final PackageManager packageManager,
+            @NonNull final InputMethodInfo imi) {
+        final ServiceInfo si = imi.getServiceInfo();
+        final ApplicationInfo ai = si.applicationInfo;
+        final String packageName = imi.getPackageName();
+        if (si == null || ai == null || packageName == null) {
+            return new ColorDrawable(Color.TRANSPARENT);
+        }
+        // We do not use ServiceInfo#loadLogo() and ServiceInfo#loadIcon here since those methods
+        // internally have some fallback rules, which we want to do manually.
+        Drawable drawable = loadDrawable(packageManager, packageName, si.logo, ai);
+        if (drawable != null) {
+            return drawable;
+        }
+        drawable = loadDrawable(packageManager, packageName, si.icon, ai);
+        if (drawable != null) {
+            return drawable;
+        }
+        // We do not use ApplicationInfo#loadLogo() and ApplicationInfo#loadIcon here since those
+        // methods internally have some fallback rules, which we want to do manually.
+        drawable = loadDrawable(packageManager, packageName, ai.logo, ai);
+        if (drawable != null) {
+            return drawable;
+        }
+        drawable = loadDrawable(packageManager, packageName, ai.icon, ai);
+        if (drawable != null) {
+            return drawable;
+        }
+        return new ColorDrawable(Color.TRANSPARENT);
+    }
+
     private void updateInputMethodPreferenceViews() {
         mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
         // Clear existing "InputMethodPreference"s
         mInputMethodPreferenceList.clear();
         List<String> permittedList = mDpm.getPermittedInputMethodsForCurrentUser();
         final Context context = getPrefContext();
+        final PackageManager packageManager = getActivity().getPackageManager();
         final List<InputMethodInfo> imis = mInputMethodSettingValues.getInputMethodList();
         final int N = (imis == null ? 0 : imis.size());
         for (int i = 0; i < N; ++i) {
             final InputMethodInfo imi = imis.get(i);
             final boolean isAllowedByOrganization = permittedList == null
                     || permittedList.contains(imi.getPackageName());
-            Drawable icon;
-            try {
-                icon = getActivity().getPackageManager().getApplicationIcon(imi.getPackageName());
-            } catch (Exception e) {
-                icon = NO_ICON;
-            }
             final InputMethodPreference pref = new InputMethodPreference(
                     context, imi, true, isAllowedByOrganization, this);
-            pref.setIcon(icon);
+            pref.setIcon(getInputMethodIcon(packageManager, imi));
             mInputMethodPreferenceList.add(pref);
         }
         final Collator collator = Collator.getInstance();
diff --git a/src/com/android/settings/inputmethod/SpellCheckersSettings.java b/src/com/android/settings/inputmethod/SpellCheckersSettings.java
index bc2a5c0..3309af2 100644
--- a/src/com/android/settings/inputmethod/SpellCheckersSettings.java
+++ b/src/com/android/settings/inputmethod/SpellCheckersSettings.java
@@ -113,7 +113,7 @@
         mSwitchBar.setChecked(isSpellCheckerEnabled);
 
         final SpellCheckerSubtype currentScs;
-        if (mCurrentSci == null) {
+        if (mCurrentSci != null) {
             currentScs = mTsm.getCurrentSpellCheckerSubtype(
                     false /* allowImplicitlySelectedSubtype */);
         } else {
diff --git a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
index fe81a81..3b36de6 100644
--- a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
@@ -113,7 +113,7 @@
             InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref);
             pref.updatePreferenceViews();
         }
-        mAddVirtualKeyboardScreen.setIcon(R.drawable.ic_add);
+        mAddVirtualKeyboardScreen.setIcon(R.drawable.ic_add_24dp);
         mAddVirtualKeyboardScreen.setOrder(N);
         getPreferenceScreen().addPreference(mAddVirtualKeyboardScreen);
     }
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index 0a48874..8c34518 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -71,6 +71,9 @@
     /** Preference key for the TTS reset speech rate preference. */
     private static final String KEY_RESET_SPEECH_RATE = "reset_speech_rate";
 
+    /** Preference key for the TTS reset speech pitch preference. */
+    private static final String KEY_RESET_SPEECH_PITCH = "reset_speech_pitch";
+
     /** Preference key for the TTS status field. */
     private static final String KEY_STATUS = "tts_status";
 
@@ -87,10 +90,11 @@
     private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
 
     /**
-     * Maximum speech rate value.
+     * Speech rate value.
      * This value should be kept in sync with the max value set in tts_settings xml.
      */
     private static final int MAX_SPEECH_RATE = 600;
+    private static final int MIN_SPEECH_RATE = 10;
 
     /**
      * Speech pitch value.
@@ -107,6 +111,7 @@
     private SeekBarPreference mDefaultPitchPref;
     private SeekBarPreference mDefaultRatePref;
     private Preference mResetSpeechRate;
+    private Preference mResetSpeechPitch;
     private Preference mPlayExample;
     private Preference mEngineStatus;
 
@@ -189,6 +194,8 @@
 
         mResetSpeechRate = findPreference(KEY_RESET_SPEECH_RATE);
         mResetSpeechRate.setOnPreferenceClickListener(this);
+        mResetSpeechPitch = findPreference(KEY_RESET_SPEECH_PITCH);
+        mResetSpeechPitch.setOnPreferenceClickListener(this);
 
         mEnginePreferenceCategory = (PreferenceCategory) findPreference(
                 KEY_ENGINE_PREFERENCE_SECTION);
@@ -252,24 +259,27 @@
     private void initSettings() {
         final ContentResolver resolver = getContentResolver();
 
-         // Set up the default rate and pitch.
-        try {
-            mDefaultPitch = android.provider.Settings.Secure.getInt(resolver, TTS_DEFAULT_PITCH);
-            mDefaultRate = android.provider.Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
-        } catch (SettingNotFoundException e) {
-            // Default rate and pitch setting not found, initialize it.
-            mDefaultPitch = TextToSpeech.Engine.DEFAULT_PITCH;
-            mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
-        }
-        mDefaultRatePref.setProgress(mDefaultRate);
+        // Set up the default rate and pitch.
+        mDefaultRate = android.provider.Settings.Secure.getInt(
+            resolver, TTS_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
+        mDefaultPitch = android.provider.Settings.Secure.getInt(
+            resolver, TTS_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
+
+        mDefaultRatePref.setProgress(getSeekBarProgressFromValue(KEY_DEFAULT_RATE, mDefaultRate));
         mDefaultRatePref.setOnPreferenceChangeListener(this);
-        mDefaultRatePref.setMax(MAX_SPEECH_RATE);
+        mDefaultRatePref.setMax(getSeekBarProgressFromValue(KEY_DEFAULT_RATE, MAX_SPEECH_RATE));
 
-        mDefaultPitchPref.setProgress(getPitchSeekBarProgressFromSpeechPitchValue(mDefaultPitch));
+        mDefaultPitchPref.setProgress(getSeekBarProgressFromValue(KEY_DEFAULT_PITCH,
+              mDefaultPitch));
         mDefaultPitchPref.setOnPreferenceChangeListener(this);
-        mDefaultPitchPref.setMax(getPitchSeekBarProgressFromSpeechPitchValue(MAX_SPEECH_PITCH));
+        mDefaultPitchPref.setMax(getSeekBarProgressFromValue(KEY_DEFAULT_PITCH,
+              MAX_SPEECH_PITCH));
 
-        mCurrentEngine = mTts.getCurrentEngine();
+        if (mTts != null) {
+            mCurrentEngine = mTts.getCurrentEngine();
+            mTts.setSpeechRate(mDefaultRate/100.0f);
+            mTts.setPitch(mDefaultPitch/100.0f);
+        }
 
         SettingsActivity activity = null;
         if (getActivity() instanceof SettingsActivity) {
@@ -292,21 +302,31 @@
     }
 
     /**
-     * The minimum pitch value should be > 0 but the minimum value of a seekbar in android
-     * is fixed at 0. Therefore, we increment the seekbar progress with MIN_SPEECH_PITCH value
-     * so that the minimum seekbar progress value is MIN_SPEECH_PITCH.
-     *     PITCH_VALUE = MIN_SPEECH_PITCH + PITCH_SEEKBAR_PROGRESS
+     * The minimum speech pitch/rate value should be > 0 but the minimum value of a seekbar in
+     * android is fixed at 0. Therefore, we increment the seekbar progress with MIN_SPEECH_VALUE
+     * so that the minimum seekbar progress value is MIN_SPEECH_PITCH/RATE.
+     *     SPEECH_VALUE = MIN_SPEECH_VALUE + SEEKBAR_PROGRESS
      */
-    private int getSpeechPitchValueFromSeekBarProgress(int progress) {
-        return MIN_SPEECH_PITCH + progress;
+    private int getValueFromSeekBarProgress(String preferenceKey, int progress) {
+        if (preferenceKey.equals(KEY_DEFAULT_RATE)) {
+            return MIN_SPEECH_RATE + progress;
+        } else if (preferenceKey.equals(KEY_DEFAULT_PITCH)) {
+            return MIN_SPEECH_PITCH + progress;
+        }
+        return progress;
     }
 
     /**
-     * Since we are appending the MIN_SPEECH_PITCH to the pitch seekbar progress, the pitch
-     * seekbar progress should be set to (pitchValue - MIN_SPEECH_PITCH).
+     * Since we are appending the MIN_SPEECH value to the speech seekbar progress, the
+     * speech seekbar progress should be set to (speechValue - MIN_SPEECH value).
      */
-    private int getPitchSeekBarProgressFromSpeechPitchValue(int pitchValue) {
-        return pitchValue - MIN_SPEECH_PITCH;
+    private int getSeekBarProgressFromValue(String preferenceKey, int value) {
+        if (preferenceKey.equals(KEY_DEFAULT_RATE)) {
+            return value - MIN_SPEECH_RATE;
+        } else if (preferenceKey.equals(KEY_DEFAULT_PITCH)) {
+            return value - MIN_SPEECH_PITCH;
+        }
+        return value;
     }
 
     /**
@@ -505,24 +525,14 @@
         if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
             updateSpeechRate((Integer) objValue);
         } else if (KEY_DEFAULT_PITCH.equals(preference.getKey())) {
-            int progress = (Integer) objValue;
-            mDefaultPitch = getSpeechPitchValueFromSeekBarProgress(progress);
-            try {
-                android.provider.Settings.Secure.putInt(getContentResolver(),
-                        TTS_DEFAULT_PITCH, mDefaultPitch);
-               if (mTts != null) {
-                   mTts.setPitch(mDefaultPitch / 100.0f);
-               }
-               if (DBG) Log.d(TAG, "TTS default pitch changed, now" + mDefaultPitch);
-           } catch (NumberFormatException e) {
-               Log.e(TAG, "could not persist default TTS pitch setting", e);
-           }
+            updateSpeechPitchValue((Integer) objValue);
         }
         return true;
     }
 
     /**
-     * Called when mPlayExample or mResetSpeechRate is clicked.
+     * Called when mPlayExample, mResetSpeechRate or mResetSpeechPitch is
+     * clicked.
      */
     @Override
     public boolean onPreferenceClick(Preference preference) {
@@ -532,15 +542,24 @@
             speakSampleText();
             return true;
         } else if (preference == mResetSpeechRate) {
-          mDefaultRatePref.setProgress(TextToSpeech.Engine.DEFAULT_RATE);
-          updateSpeechRate(TextToSpeech.Engine.DEFAULT_RATE);
+          int speechRateSeekbarProgress = getSeekBarProgressFromValue(
+              KEY_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
+          mDefaultRatePref.setProgress(speechRateSeekbarProgress);
+          updateSpeechRate(speechRateSeekbarProgress);
+          return true;
+        } else if (preference == mResetSpeechPitch) {
+          int pitchSeekbarProgress = getSeekBarProgressFromValue(
+              KEY_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
+          mDefaultPitchPref.setProgress(pitchSeekbarProgress);
+          updateSpeechPitchValue(pitchSeekbarProgress);
           return true;
         }
         return false;
     }
 
-    private void updateSpeechRate(int speechRate) {
-        mDefaultRate = speechRate;
+    private void updateSpeechRate(int speechRateSeekBarProgress) {
+        mDefaultRate = getValueFromSeekBarProgress(KEY_DEFAULT_RATE,
+            speechRateSeekBarProgress);
         try {
             android.provider.Settings.Secure.putInt(getContentResolver(),
                     TTS_DEFAULT_RATE, mDefaultRate);
@@ -554,6 +573,22 @@
         return;
     }
 
+    private void updateSpeechPitchValue(int speechPitchSeekBarProgress) {
+        mDefaultPitch = getValueFromSeekBarProgress(KEY_DEFAULT_PITCH,
+            speechPitchSeekBarProgress);
+        try {
+            android.provider.Settings.Secure.putInt(getContentResolver(),
+                    TTS_DEFAULT_PITCH, mDefaultPitch);
+            if (mTts != null) {
+                mTts.setPitch(mDefaultPitch / 100.0f);
+            }
+            if (DBG) Log.d(TAG, "TTS default pitch changed, now" + mDefaultPitch);
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "could not persist default TTS pitch setting", e);
+        }
+        return;
+    }
+
     private void updateWidgetState(boolean enable) {
         mPlayExample.setEnabled(enable);
         mDefaultRatePref.setEnabled(enable);
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index 2ff404d..f064050 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -26,6 +26,8 @@
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.widget.Switch;
 import android.widget.Toast;
@@ -35,6 +37,8 @@
 import com.android.settings.R;
 import com.android.settings.search.Index;
 import com.android.settings.widget.SwitchBar;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.WirelessUtils;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -136,6 +140,9 @@
     }
 
     private void handleWifiStateChanged(int state) {
+        // Clear any previous state
+        mSwitchBar.setDisabledByAdmin(null);
+
         switch (state) {
             case WifiManager.WIFI_STATE_ENABLING:
                 mSwitchBar.setEnabled(false);
@@ -158,6 +165,16 @@
                 mSwitchBar.setEnabled(true);
                 updateSearchIndex(false);
         }
+        if (mayDisableTethering(!mSwitchBar.isChecked())) {
+            if (RestrictedLockUtils.hasBaseUserRestriction(mContext,
+                    UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) {
+                mSwitchBar.setEnabled(false);
+            } else {
+                final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+                    UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId());
+                mSwitchBar.setDisabledByAdmin(admin);
+            }
+        }
     }
 
     private void updateSearchIndex(boolean isWiFiOn) {
@@ -206,9 +223,7 @@
         }
 
         // Disable tethering if enabling Wifi
-        int wifiApState = mWifiManager.getWifiApState();
-        if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
-                (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+        if (mayDisableTethering(isChecked)) {
             mWifiManager.setWifiApEnabled(null, false);
         }
         MetricsLogger.action(mContext,
@@ -219,4 +234,10 @@
             Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
         }
     }
+
+    private boolean mayDisableTethering(boolean isChecked) {
+        final int wifiApState = mWifiManager.getWifiApState();
+        return isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+            (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED));
+    }
 }