Save app toggle state as soon as possible

Delaying applying the states till onPause() sometimes results in the apps
disappearing slowly as the new user is booting up, causing failed queued up
broadcasts that result in crash dialogs. This happens mainly when the user
switch is initiated via QuickSettings->LockScreen->Switch while the App
restrictions screen is still showing. The onPause() gets called when
SetupWizard actually takes focus, which is quite late, as boot completed
and other events have already been queued.

Apply the initial toggles right away and apply any user changes when primary
is going to background, or onPause(), whichever comes first.

Bug: 8685927

Also ensure that apps with restrictions get a chance to persist their defaults
as soon as they are toggled on. The user may never actually click on the settings
icon for the app (which was the only way they were getting persisted before).

Some new strings for an upcoming change.

Change-Id: I96f453d066a91c6b15eafe9a6ce3f42d98bf5e33
This commit is contained in:
Amith Yamasani
2013-04-26 14:55:01 -07:00
parent a7a93784d1
commit 7b56d115ba
2 changed files with 56 additions and 13 deletions

View File

@@ -4328,6 +4328,10 @@
<string name="user_add_user_menu">Add user or profile</string> <string name="user_add_user_menu">Add user or profile</string>
<!-- User settings summary for a restricted profile [CHAR LIMIT=50] --> <!-- User settings summary for a restricted profile [CHAR LIMIT=50] -->
<string name="user_summary_restricted_profile">Restricted profile</string> <string name="user_summary_restricted_profile">Restricted profile</string>
<!-- User settings warning that restricted profile needs a screen lock [CHAR LIMIT=NONE] -->
<string name="user_need_lock_message">Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data.</string>
<!-- User settings dialog button to set screen lock [CHAR LIMIT=25] -->
<string name="user_set_lock_button">Set lock</string>
<!-- User summary to indicate that user is currently not set up [CHAR LIMIT=100] --> <!-- User summary to indicate that user is currently not set up [CHAR LIMIT=100] -->
<string name="user_summary_not_set_up">Not set up</string> <string name="user_summary_not_set_up">Not set up</string>
<!-- User summary to indicate that restricted profile is currently not set up [CHAR LIMIT=100] --> <!-- User summary to indicate that restricted profile is currently not set up [CHAR LIMIT=100] -->

View File

@@ -26,6 +26,7 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.RestrictionEntry; import android.content.RestrictionEntry;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager; import android.content.pm.IPackageManager;
@@ -141,6 +142,20 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
private EditUserPhotoController mEditUserPhotoController; private EditUserPhotoController mEditUserPhotoController;
private BroadcastReceiver mUserBackgrounding = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Update the user's app selection right away without waiting for a pause
// onPause() might come in too late, causing apps to disappear after broadcasts
// have been scheduled during user startup.
if (mAppListChanged) {
if (DEBUG) Log.d(TAG, "User backgrounding, update app list");
updateUserAppList();
if (DEBUG) Log.d(TAG, "User backgrounding, done updating app list");
}
}
};
static class SelectableAppInfo { static class SelectableAppInfo {
String packageName; String packageName;
CharSequence appName; CharSequence appName;
@@ -257,7 +272,6 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
super.onCreate(icicle); super.onCreate(icicle);
if (icicle != null) { if (icicle != null) {
mNewUser = icicle.getBoolean(EXTRA_NEW_USER, false);
mUser = new UserHandle(icicle.getInt(EXTRA_USER_ID)); mUser = new UserHandle(icicle.getInt(EXTRA_USER_ID));
} else { } else {
Bundle args = getArguments(); Bundle args = getArguments();
@@ -292,12 +306,13 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_NEW_USER, mNewUser);
outState.putInt(EXTRA_USER_ID, mUser.getIdentifier()); outState.putInt(EXTRA_USER_ID, mUser.getIdentifier());
} }
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
getActivity().registerReceiver(mUserBackgrounding,
new IntentFilter(Intent.ACTION_USER_BACKGROUND));
mAppListChanged = false; mAppListChanged = false;
new AppLoadingTask().execute((Void[]) null); new AppLoadingTask().execute((Void[]) null);
@@ -311,6 +326,8 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
mNewUser = false;
getActivity().unregisterReceiver(mUserBackgrounding);
if (mAppListChanged) { if (mAppListChanged) {
new Thread() { new Thread() {
public void run() { public void run() {
@@ -336,6 +353,9 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
ApplicationInfo info = ipm.getApplicationInfo(packageName, 0, userId); ApplicationInfo info = ipm.getApplicationInfo(packageName, 0, userId);
if (info == null || info.enabled == false) { if (info == null || info.enabled == false) {
ipm.installExistingPackageAsUser(packageName, mUser.getIdentifier()); ipm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
if (DEBUG) {
Log.d(TAG, "Installing " + packageName);
}
} }
} catch (RemoteException re) { } catch (RemoteException re) {
} }
@@ -346,6 +366,9 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
if (info != null) { if (info != null) {
ipm.deletePackageAsUser(entry.getKey(), null, mUser.getIdentifier(), ipm.deletePackageAsUser(entry.getKey(), null, mUser.getIdentifier(),
PackageManager.DELETE_SYSTEM_APP); PackageManager.DELETE_SYSTEM_APP);
if (DEBUG) {
Log.d(TAG, "Uninstalling " + packageName);
}
} }
} catch (RemoteException re) { } catch (RemoteException re) {
} }
@@ -597,6 +620,12 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
i++; i++;
} }
} }
// If this is the first time for a new profile, install/uninstall default apps for profile
// to avoid taking the hit in onPause(), which can cause race conditions on user switch.
if (mNewUser && mFirstTime) {
mFirstTime = false;
updateUserAppList();
}
} }
private class AppLabelComparator implements Comparator<SelectableAppInfo> { private class AppLabelComparator implements Comparator<SelectableAppInfo> {
@@ -648,8 +677,13 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
toggleAppPanel(pref); toggleAppPanel(pref);
} else if (!pref.isImmutable()) { } else if (!pref.isImmutable()) {
pref.setChecked(!pref.isChecked()); pref.setChecked(!pref.isChecked());
mSelectedPackages.put(pref.getKey().substring(PKG_PREFIX.length()), final String packageName = pref.getKey().substring(PKG_PREFIX.length());
pref.isChecked()); mSelectedPackages.put(packageName, pref.isChecked());
if (pref.isChecked() && pref.hasSettings
&& pref.restrictions == null) {
// The restrictions have not been initialized, get and save them
requestRestrictionsForApp(packageName, pref);
}
mAppListChanged = true; mAppListChanged = true;
updateAllEntries(pref.getKey(), pref.isChecked()); updateAllEntries(pref.getKey(), pref.isChecked());
} }
@@ -722,21 +756,26 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
getActivity(), mUser); getActivity(), mUser);
onRestrictionsReceived(preference, packageName, restrictions); onRestrictionsReceived(preference, packageName, restrictions);
} else { } else {
Bundle oldEntries = requestRestrictionsForApp(packageName, preference);
mUserManager.getApplicationRestrictions(packageName, mUser);
Intent intent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
intent.setPackage(packageName);
intent.putExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE, oldEntries);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
getActivity().sendOrderedBroadcast(intent, null,
new RestrictionsResultReceiver(packageName, preference),
null, Activity.RESULT_OK, null, null);
} }
} }
preference.panelOpen = !preference.panelOpen; preference.panelOpen = !preference.panelOpen;
} }
} }
private void requestRestrictionsForApp(String packageName,
AppRestrictionsPreference preference) {
Bundle oldEntries =
mUserManager.getApplicationRestrictions(packageName, mUser);
Intent intent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
intent.setPackage(packageName);
intent.putExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE, oldEntries);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
getActivity().sendOrderedBroadcast(intent, null,
new RestrictionsResultReceiver(packageName, preference),
null, Activity.RESULT_OK, null, null);
}
class RestrictionsResultReceiver extends BroadcastReceiver { class RestrictionsResultReceiver extends BroadcastReceiver {
private static final String CUSTOM_RESTRICTIONS_INTENT = Intent.EXTRA_RESTRICTIONS_INTENT; private static final String CUSTOM_RESTRICTIONS_INTENT = Intent.EXTRA_RESTRICTIONS_INTENT;