Merge "Apply restrictions right away instead of on exit"
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index 495f3fd..3777a8e 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -29,6 +29,7 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.SystemProperties;
+import android.os.UserManager;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.util.Log;
@@ -54,6 +55,7 @@
     private static final String TAG = "MasterClear";
 
     private static final int KEYGUARD_REQUEST = 55;
+    private static final int PIN_REQUEST = 56;
 
     static final String ERASE_EXTERNAL_EXTRA = "erase_sd";
 
@@ -61,6 +63,7 @@
     private Button mInitiateButton;
     private View mExternalStorageContainer;
     private CheckBox mExternalStorage;
+    private boolean mPinConfirmed;
 
     /**
      * Keyguard validation is run using the standard {@link ConfirmLockPattern}
@@ -76,11 +79,25 @@
                         res.getText(R.string.master_clear_gesture_explanation));
     }
 
+    private boolean runRestrictionsChallenge() {
+        if (UserManager.get(getActivity()).hasRestrictionsPin()) {
+            startActivityForResult(
+                    new Intent(Intent.ACTION_RESTRICTIONS_PIN_CHALLENGE), PIN_REQUEST);
+            return true;
+        }
+        return false;
+    }
+
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
 
-        if (requestCode != KEYGUARD_REQUEST) {
+        if (requestCode == PIN_REQUEST) {
+            if (resultCode == Activity.RESULT_OK) {
+                mPinConfirmed = true;
+            }
+            return;
+        } else if (requestCode != KEYGUARD_REQUEST) {
             return;
         }
 
@@ -109,6 +126,10 @@
     private final Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
 
         public void onClick(View v) {
+            mPinConfirmed = false;
+            if (runRestrictionsChallenge()) {
+                return;
+            }
             if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
                 showFinalConfirmation();
             }
@@ -239,4 +260,17 @@
         establishInitialState();
         return mContentView;
     }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        // If this is the second step after restrictions pin challenge
+        if (mPinConfirmed) {
+            mPinConfirmed = false;
+            if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
+                showFinalConfirmation();
+            }
+        }
+    }
 }
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
index 2f99d11..0e15cec 100644
--- a/src/com/android/settings/users/AppRestrictionsFragment.java
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -57,6 +57,7 @@
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.ViewGroup;
+import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.Switch;
@@ -85,7 +86,9 @@
 
     protected PackageManager mPackageManager;
     protected UserManager mUserManager;
+    protected IPackageManager mIPm;
     protected UserHandle mUser;
+    private PackageInfo mSysPackageInfo;
 
     private PreferenceGroup mAppList;
 
@@ -129,6 +132,13 @@
         }
     };
 
+    private BroadcastReceiver mPackageObserver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            onPackageChanged(intent);
+        }
+    };
+
     static class SelectableAppInfo {
         String packageName;
         CharSequence appName;
@@ -147,9 +157,9 @@
         private boolean hasSettings;
         private OnClickListener listener;
         private ArrayList<RestrictionEntry> restrictions;
-        boolean panelOpen;
+        private boolean mPanelOpen;
         private boolean immutable;
-        List<Preference> childPreferences = new ArrayList<Preference>();
+        private List<Preference> mChildren = new ArrayList<Preference>();
         private final ColorFilter grayscaleFilter;
 
         AppRestrictionsPreference(Context context, OnClickListener listener) {
@@ -204,6 +214,14 @@
             return restrictions;
         }
 
+        boolean isPanelOpen() {
+            return mPanelOpen;
+        }
+
+        List<Preference> getChildren() {
+            return mChildren;
+        }
+
         @Override
         protected void onBindView(View view) {
             super.onBindView(view);
@@ -222,13 +240,13 @@
             ViewGroup widget = (ViewGroup) view.findViewById(android.R.id.widget_frame);
             widget.setEnabled(!isImmutable());
             if (widget.getChildCount() > 0) {
-                final Switch switchView = (Switch) widget.getChildAt(0);
-                switchView.setEnabled(!isImmutable());
-                switchView.setTag(this);
-                switchView.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+                final Switch toggle = (Switch) widget.getChildAt(0);
+                toggle.setEnabled(!isImmutable());
+                toggle.setTag(this);
+                toggle.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                     @Override
                     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                        listener.onClick(switchView);
+                        listener.onClick(toggle);
                     }
                 });
             }
@@ -253,9 +271,15 @@
         }
 
         mPackageManager = getActivity().getPackageManager();
+        mIPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
         mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
         mRestrictedProfile = mUserManager.getUserInfo(mUser.getIdentifier()).isRestricted();
-
+        try {
+            mSysPackageInfo = mPackageManager.getPackageInfo("android",
+                PackageManager.GET_SIGNATURES);
+        } catch (NameNotFoundException nnfe) {
+            // ?
+        }
         addPreferencesFromResource(R.xml.app_restrictions);
         mAppList = getAppPreferenceGroup();
     }
@@ -266,21 +290,30 @@
         outState.putInt(EXTRA_USER_ID, mUser.getIdentifier());
     }
 
+    @Override
     public void onResume() {
         super.onResume();
 
         getActivity().registerReceiver(mUserBackgrounding,
                 new IntentFilter(Intent.ACTION_USER_BACKGROUND));
+        IntentFilter packageFilter = new IntentFilter();
+        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageFilter.addDataScheme("package");
+        getActivity().registerReceiver(mPackageObserver, packageFilter);
+
         mAppListChanged = false;
         if (mAppLoadingTask == null || mAppLoadingTask.getStatus() == AsyncTask.Status.FINISHED) {
             mAppLoadingTask = new AppLoadingTask().execute((Void[]) null);
         }
     }
 
+    @Override
     public void onPause() {
         super.onPause();
         mNewUser = false;
         getActivity().unregisterReceiver(mUserBackgrounding);
+        getActivity().unregisterReceiver(mPackageObserver);
         if (mAppListChanged) {
             new Thread() {
                 public void run() {
@@ -290,6 +323,20 @@
         }
     }
 
+    private void onPackageChanged(Intent intent) {
+        String action = intent.getAction();
+        String packageName = intent.getData().getSchemeSpecificPart();
+        // Package added, check if the preference needs to be enabled
+        AppRestrictionsPreference pref = (AppRestrictionsPreference)
+                findPreference(getKeyForPackage(packageName));
+        if (pref == null) return;
+
+        if ((Intent.ACTION_PACKAGE_ADDED.equals(action) && pref.isChecked())
+                || (Intent.ACTION_PACKAGE_REMOVED.equals(action) && !pref.isChecked())) {
+            pref.setEnabled(true);
+        }
+    }
+
     protected PreferenceGroup getAppPreferenceGroup() {
         return getPreferenceScreen();
     }
@@ -306,8 +353,6 @@
     }
 
     private void applyUserAppsStates() {
-        IPackageManager ipm = IPackageManager.Stub.asInterface(
-                ServiceManager.getService("package"));
         final int userId = mUser.getIdentifier();
         if (!mUserManager.getUserInfo(userId).isRestricted() && userId != UserHandle.myUserId()) {
             Log.e(TAG, "Cannot apply application restrictions on another user!");
@@ -315,47 +360,64 @@
         }
         for (Map.Entry<String,Boolean> entry : mSelectedPackages.entrySet()) {
             String packageName = entry.getKey();
-            if (entry.getValue()) {
-                // Enable selected apps
-                try {
-                    ApplicationInfo info = ipm.getApplicationInfo(packageName,
-                            PackageManager.GET_UNINSTALLED_PACKAGES, userId);
-                    if (info == null || info.enabled == false) {
-                        ipm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
-                        if (DEBUG) {
-                            Log.d(TAG, "Installing " + packageName);
-                        }
+            boolean enabled = entry.getValue();
+            applyUserAppState(packageName, enabled);
+        }
+    }
+
+    private void applyUserAppState(String packageName, boolean enabled) {
+        final int userId = mUser.getIdentifier();
+        if (enabled) {
+            // Enable selected apps
+            try {
+                ApplicationInfo info = mIPm.getApplicationInfo(packageName,
+                        PackageManager.GET_UNINSTALLED_PACKAGES, userId);
+                if (info == null || info.enabled == false
+                        || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
+                    mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
+                    if (DEBUG) {
+                        Log.d(TAG, "Installing " + packageName);
                     }
-                    if (info != null && (info.flags&ApplicationInfo.FLAG_BLOCKED) != 0
-                            && (info.flags&ApplicationInfo.FLAG_INSTALLED) != 0) {
-                        ipm.setApplicationBlockedSettingAsUser(packageName, false, userId);
-                        if (DEBUG) {
-                            Log.d(TAG, "Unblocking " + packageName);
-                        }
-                    }
-                } catch (RemoteException re) {
                 }
-            } else {
-                // Blacklist all other apps, system or downloaded
-                try {
-                    ApplicationInfo info = ipm.getApplicationInfo(packageName, 0, userId);
-                    if (info != null) {
-                        if (mRestrictedProfile) {
-                            ipm.deletePackageAsUser(entry.getKey(), null, mUser.getIdentifier(),
-                                    PackageManager.DELETE_SYSTEM_APP);
-                            if (DEBUG) {
-                                Log.d(TAG, "Uninstalling " + packageName);
-                            }
-                        } else {
-                            ipm.setApplicationBlockedSettingAsUser(packageName, true, userId);
-                            if (DEBUG) {
-                                Log.d(TAG, "Blocking " + packageName);
-                            }
-                        }
+                if (info != null && (info.flags&ApplicationInfo.FLAG_BLOCKED) != 0
+                        && (info.flags&ApplicationInfo.FLAG_INSTALLED) != 0) {
+                    disableUiForPackage(packageName);
+                    mIPm.setApplicationBlockedSettingAsUser(packageName, false, userId);
+                    if (DEBUG) {
+                        Log.d(TAG, "Unblocking " + packageName);
                     }
-                } catch (RemoteException re) {
                 }
+            } catch (RemoteException re) {
             }
+        } else {
+            // Blacklist all other apps, system or downloaded
+            try {
+                ApplicationInfo info = mIPm.getApplicationInfo(packageName, 0, userId);
+                if (info != null) {
+                    if (mRestrictedProfile) {
+                        mIPm.deletePackageAsUser(packageName, null, mUser.getIdentifier(),
+                                PackageManager.DELETE_SYSTEM_APP);
+                        if (DEBUG) {
+                            Log.d(TAG, "Uninstalling " + packageName);
+                        }
+                    } else {
+                        disableUiForPackage(packageName);
+                        mIPm.setApplicationBlockedSettingAsUser(packageName, true, userId);
+                        if (DEBUG) {
+                            Log.d(TAG, "Blocking " + packageName);
+                        }
+                    }
+                }
+            } catch (RemoteException re) {
+            }
+        }
+    }
+
+    private void disableUiForPackage(String packageName) {
+        AppRestrictionsPreference pref = (AppRestrictionsPreference) findPreference(
+                getKeyForPackage(packageName));
+        if (pref != null) {
+            pref.setEnabled(false);
         }
     }
 
@@ -457,7 +519,7 @@
         final Context context = getActivity();
         if (context == null) return;
         final PackageManager pm = mPackageManager;
-        IPackageManager ipm = AppGlobals.getPackageManager();
+        final IPackageManager ipm = mIPm;
 
         final HashSet<String> excludePackages = new HashSet<String>();
         addSystemImes(excludePackages);
@@ -552,6 +614,11 @@
         }
     }
 
+    private boolean isPlatformSigned(PackageInfo pi) {
+        return (pi != null && pi.signatures != null &&
+                    mSysPackageInfo.signatures[0].equals(pi.signatures[0]));
+    }
+
     private boolean isAppEnabledForUser(PackageInfo pi) {
         if (pi == null) return false;
         final int flags = pi.applicationInfo.flags;
@@ -564,7 +631,8 @@
         final Context context = getActivity();
         if (context == null) return;
         final PackageManager pm = mPackageManager;
-        IPackageManager ipm = AppGlobals.getPackageManager();
+        final IPackageManager ipm = mIPm;
+
         mAppList.removeAll();
         Intent restrictionsIntent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
         final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(restrictionsIntent, 0);
@@ -583,7 +651,7 @@
                     p.setSummary(context.getString(R.string.user_restrictions_controlled_by,
                             app.masterEntry.activityName));
                 }
-                p.setKey(PKG_PREFIX + packageName);
+                p.setKey(getKeyForPackage(packageName));
                 p.setSettingsEnabled(hasSettings || isSettingsApp);
                 p.setPersistent(false);
                 p.setOnPreferenceChangeListener(this);
@@ -591,10 +659,11 @@
                 PackageInfo pi = null;
                 try {
                     pi = ipm.getPackageInfo(packageName,
-                            PackageManager.GET_UNINSTALLED_PACKAGES, mUser.getIdentifier());
+                            PackageManager.GET_UNINSTALLED_PACKAGES
+                            | PackageManager.GET_SIGNATURES, mUser.getIdentifier());
                 } catch (RemoteException e) {
                 }
-                if (pi != null && pi.requiredForAllUsers) {
+                if (pi != null && (pi.requiredForAllUsers || isPlatformSigned(pi))) {
                     p.setChecked(true);
                     p.setImmutable(true);
                     // If the app is required and has no restrictions, skip showing it
@@ -602,10 +671,10 @@
                     // Get and populate the defaults, since the user is not going to be
                     // able to toggle this app ON (it's ON by default and immutable).
                     // Only do this for restricted profiles, not single-user restrictions
-                    if (hasSettings && mRestrictedProfile) {
+                    if (hasSettings) {
                         requestRestrictionsForApp(packageName, p);
                     }
-                } else if (!mNewUser && isAppEnabledForUser(pi)) { /*appInfoListHasPackage(mUserApps, packageName)*/
+                } else if (!mNewUser && isAppEnabledForUser(pi)) {
                     p.setChecked(true);
                 }
                 if (mRestrictedProfile
@@ -640,6 +709,10 @@
         }
     }
 
+    private String getKeyForPackage(String packageName) {
+        return PKG_PREFIX + packageName;
+    }
+
     private class AppLabelComparator implements Comparator<SelectableAppInfo> {
 
         @Override
@@ -686,6 +759,10 @@
                     requestRestrictionsForApp(packageName, pref);
                 }
                 mAppListChanged = true;
+                // If it's not a restricted profile, apply the changes immediately
+                if (!mRestrictedProfile) {
+                    applyUserAppState(packageName, pref.isChecked());
+                }
                 updateAllEntries(pref.getKey(), pref.isChecked());
             }
         }
@@ -742,11 +819,11 @@
 
     private void toggleAppPanel(AppRestrictionsPreference preference) {
         if (preference.getKey().startsWith(PKG_PREFIX)) {
-            if (preference.panelOpen) {
-                for (Preference p : preference.childPreferences) {
+            if (preference.mPanelOpen) {
+                for (Preference p : preference.mChildren) {
                     mAppList.removePreference(p);
                 }
-                preference.childPreferences.clear();
+                preference.mChildren.clear();
             } else {
                 String packageName = preference.getKey().substring(PKG_PREFIX.length());
                 if (packageName.equals(getActivity().getPackageName())) {
@@ -758,7 +835,7 @@
                     requestRestrictionsForApp(packageName, preference);
                 }
             }
-            preference.panelOpen = !preference.panelOpen;
+            preference.mPanelOpen = !preference.mPanelOpen;
         }
     }
 
@@ -795,8 +872,10 @@
             Intent restrictionsIntent = (Intent) results.getParcelable(CUSTOM_RESTRICTIONS_INTENT);
             if (restrictions != null && restrictionsIntent == null) {
                 onRestrictionsReceived(preference, packageName, restrictions);
-                mUserManager.setApplicationRestrictions(packageName,
-                        RestrictionUtils.restrictionsToBundle(restrictions), mUser);
+                if (mRestrictedProfile) {
+                    mUserManager.setApplicationRestrictions(packageName,
+                            RestrictionUtils.restrictionsToBundle(restrictions), mUser);
+                }
             } else if (restrictionsIntent != null) {
                 final Intent customIntent = restrictionsIntent;
                 if (restrictions != null) {
@@ -817,7 +896,7 @@
                 });
                 p.setPersistent(false);
                 p.setOrder(preference.getOrder() + 1);
-                preference.childPreferences.add(p);
+                preference.mChildren.add(p);
                 mAppList.addPreference(p);
                 preference.setRestrictions(restrictions);
             }
@@ -876,7 +955,7 @@
                         + entry.getKey());
                 mAppList.addPreference(p);
                 p.setOnPreferenceChangeListener(AppRestrictionsFragment.this);
-                preference.childPreferences.add(p);
+                preference.mChildren.add(p);
                 count++;
             }
         }
@@ -946,10 +1025,13 @@
         if (preference.getKey().startsWith(PKG_PREFIX)) {
             AppRestrictionsPreference arp = (AppRestrictionsPreference) preference;
             if (!arp.isImmutable()) {
-                arp.setChecked(!arp.isChecked());
-                mSelectedPackages.put(arp.getKey().substring(PKG_PREFIX.length()), arp.isChecked());
-                updateAllEntries(arp.getKey(), arp.isChecked());
+                final String packageName = arp.getKey().substring(PKG_PREFIX.length());
+                final boolean newEnabledState = !arp.isChecked();
+                arp.setChecked(newEnabledState);
+                mSelectedPackages.put(packageName, newEnabledState);
+                updateAllEntries(arp.getKey(), newEnabledState);
                 mAppListChanged = true;
+                applyUserAppState(packageName, newEnabledState);
             }
             return true;
         }
diff --git a/src/com/android/settings/users/RestrictionSettings.java b/src/com/android/settings/users/RestrictionSettings.java
index 789cee4..6ffea16 100644
--- a/src/com/android/settings/users/RestrictionSettings.java
+++ b/src/com/android/settings/users/RestrictionSettings.java
@@ -29,6 +29,8 @@
 
 import com.android.settings.R;
 
+import org.junit.internal.matchers.IsCollectionContaining;
+
 import java.util.List;
 
 /**
@@ -41,6 +43,7 @@
     private static final int MENU_RESET = Menu.FIRST + 1;
     private static final int MENU_CHANGE_PIN = Menu.FIRST + 2;
 
+    private static final String KEY_CHALLENGE_SUCCEEDED = "chsc";
     private static final String KEY_CHALLENGE_REQUESTED = "chrq";
 
     private boolean mChallengeSucceeded;
@@ -50,16 +53,19 @@
         super.onCreate(icicle);
 
         init(icicle);
-        mChallengeSucceeded = false;
-        mChallengeRequested = icicle != null
-                ? icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false)
-                : false;
+        if (icicle != null) {
+            mChallengeSucceeded = icicle.getBoolean(KEY_CHALLENGE_SUCCEEDED, false);
+            mChallengeRequested = icicle.getBoolean(KEY_CHALLENGE_REQUESTED, false);
+        }
         setHasOptionsMenu(true);
     }
 
     public void onResume() {
         super.onResume();
+        ensurePin();
+    }
 
+    private void ensurePin() {
         if (!mChallengeSucceeded) {
             getListView().setEnabled(false);
             final UserManager um = UserManager.get(getActivity());
@@ -81,24 +87,13 @@
 
     private void resetAndRemovePin() {
         final UserManager um = UserManager.get(getActivity());
-        final PackageManager pm = getActivity().getPackageManager();
-        List<ApplicationInfo> installedApps = pm.getInstalledApplications(
-                PackageManager.GET_UNINSTALLED_PACKAGES);
-        UserHandle user = android.os.Process.myUserHandle();
-        for (ApplicationInfo info: installedApps) {
-            if ((info.flags & ApplicationInfo.FLAG_BLOCKED) != 0
-                    && (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
-                pm.setApplicationBlockedSettingAsUser(info.packageName, false, user);
-            }
-        }
-        um.changeRestrictionsPin(null);
+        um.removeRestrictions();
         clearSelectedApps();
         finishFragment();
     }
 
     private void changePin() {
         final UserManager um = UserManager.get(getActivity());
-        um.changeRestrictionsPin(null);
         Intent requestPin = new Intent("android.intent.action.RESTRICTIONS_PIN_CREATE");
         startActivityForResult(requestPin, REQUEST_PIN_CHALLENGE);
     }
@@ -120,7 +115,11 @@
 
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
+
         outState.putBoolean(KEY_CHALLENGE_REQUESTED, mChallengeRequested);
+        if (getActivity().isChangingConfigurations()) {
+            outState.putBoolean(KEY_CHALLENGE_SUCCEEDED, mChallengeSucceeded);
+        }
     }
 
     @Override