From 07025891683aef83d850b0a91b37aa75b11ce33c Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Thu, 26 Feb 2015 16:19:34 -0500 Subject: [PATCH] Merge profiles apps into app list Remove the spinner and add all apps into one list and badge the managed items. Bug: 19443900 Change-Id: I9ccacc1b503da2663b9a3945f4fd6051ae95e328 --- res/layout/manage_applications_content.xml | 5 - .../settings/applications/AppInfoBase.java | 5 +- .../applications/AppStorageSettings.java | 6 +- .../applications/ApplicationsState.java | 176 ++++++++++++++---- .../applications/InstalledAppDetails.java | 5 +- .../applications/ManageApplications.java | 60 ++---- 6 files changed, 162 insertions(+), 95 deletions(-) diff --git a/res/layout/manage_applications_content.xml b/res/layout/manage_applications_content.xml index db22529bf53..364a00265e8 100644 --- a/res/layout/manage_applications_content.xml +++ b/res/layout/manage_applications_content.xml @@ -25,11 +25,6 @@ android:orientation="vertical" android:background="@drawable/default_preference_background"> - - ALPHA_COMPARATOR = new Comparator() { @@ -265,6 +277,8 @@ public class ApplicationsState { final Context mContext; final PackageManager mPm; + final IPackageManager mIpm; + final UserManager mUm; final int mRetrieveFlags; PackageIntentReceiver mPackageIntentReceiver; @@ -276,11 +290,14 @@ public class ApplicationsState { final ArrayList mSessions = new ArrayList(); final ArrayList mRebuildingSessions = new ArrayList(); final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges(); - final HashMap mEntriesMap = new HashMap(); + // Map: userid => (Map: package name => AppEntry) + final SparseArray> mEntriesMap = + new SparseArray>(); final ArrayList mAppEntries = new ArrayList(); List mApplications = new ArrayList(); long mCurId = 1; String mCurComputingSizePkg; + int mCurComputingSizeUserId; boolean mSessionsChanged; // Temporary for dispatching session callbacks. Only touched by main thread. @@ -301,6 +318,11 @@ public class ApplicationsState { sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(this, sdFilter); + // Register for events related to user creation/deletion. + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_ADDED); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(this, userFilter); } void unregisterReceiver() { mContext.unregisterReceiver(this); @@ -311,15 +333,21 @@ public class ApplicationsState { if (Intent.ACTION_PACKAGE_ADDED.equals(actionStr)) { Uri data = intent.getData(); String pkgName = data.getEncodedSchemeSpecificPart(); - addPackage(pkgName); + for (int i = 0; i < mEntriesMap.size(); i++) { + addPackage(pkgName, mEntriesMap.keyAt(i)); + } } else if (Intent.ACTION_PACKAGE_REMOVED.equals(actionStr)) { Uri data = intent.getData(); String pkgName = data.getEncodedSchemeSpecificPart(); - removePackage(pkgName); + for (int i = 0; i < mEntriesMap.size(); i++) { + removePackage(pkgName, mEntriesMap.keyAt(i)); + } } else if (Intent.ACTION_PACKAGE_CHANGED.equals(actionStr)) { Uri data = intent.getData(); String pkgName = data.getEncodedSchemeSpecificPart(); - invalidatePackage(pkgName); + for (int i = 0; i < mEntriesMap.size(); i++) { + invalidatePackage(pkgName, mEntriesMap.keyAt(i)); + } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(actionStr) || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(actionStr)) { // When applications become available or unavailable (perhaps because @@ -336,9 +364,15 @@ public class ApplicationsState { boolean avail = Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(actionStr); if (avail) { for (String pkgName : pkgList) { - invalidatePackage(pkgName); + for (int i = 0; i < mEntriesMap.size(); i++) { + invalidatePackage(pkgName, mEntriesMap.keyAt(i)); + } } } + } else if (Intent.ACTION_USER_ADDED.equals(actionStr)) { + addUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); + } else if (Intent.ACTION_USER_REMOVED.equals(actionStr)) { + removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); } } } @@ -426,6 +460,11 @@ public class ApplicationsState { private ApplicationsState(Application app) { mContext = app; mPm = mContext.getPackageManager(); + mIpm = AppGlobals.getPackageManager(); + mUm = (UserManager) app.getSystemService(Context.USER_SERVICE); + for (UserHandle user : mUm.getUserProfiles()) { + mEntriesMap.put(user.getIdentifier(), new HashMap()); + } mThread = new HandlerThread("ApplicationsState.Loader", Process.THREAD_PRIORITY_BACKGROUND); mThread.start(); @@ -630,15 +669,22 @@ public class ApplicationsState { mPackageIntentReceiver = new PackageIntentReceiver(); mPackageIntentReceiver.registerReceiver(); } - mApplications = mPm.getInstalledApplications(mRetrieveFlags); - if (mApplications == null) { - mApplications = new ArrayList(); + mApplications = new ArrayList(); + for (UserHandle user : mUm.getUserProfiles()) { + try { + ParceledListSlice list = + mIpm.getInstalledApplications(mRetrieveFlags, user.getIdentifier()); + mApplications.addAll(list.getList()); + } catch (RemoteException e) { + } } if (mInterestingConfigChanges.applyNewConfig(mContext.getResources())) { // If an interesting part of the configuration has changed, we // should completely reload the app entries. - mEntriesMap.clear(); + for (int i = 0; i < mEntriesMap.size(); i++) { + mEntriesMap.valueAt(i).clear(); + } mAppEntries.clear(); } else { for (int i=0; i=0; i--) { - if (mApplications.get(i).packageName.equals(pkgName)) { + ApplicationInfo appInfo = mApplications.get(i); + if (appInfo.packageName.equals(pkgName) + && UserHandle.getUserId(appInfo.uid) == userId) { return i; } } return -1; } - void addPackage(String pkgName) { + void addPackage(String pkgName, int userId) { try { synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "addPackage acquired lock"); @@ -762,12 +815,15 @@ public class ApplicationsState { if (DEBUG_LOCKING) Log.v(TAG, "addPackage release lock: not resumed"); return; } - if (indexOfApplicationInfoLocked(pkgName) >= 0) { + if (indexOfApplicationInfoLocked(pkgName, userId) >= 0) { if (DEBUG) Log.i(TAG, "Package already exists!"); if (DEBUG_LOCKING) Log.v(TAG, "addPackage release lock: already exists"); return; } - ApplicationInfo info = mPm.getApplicationInfo(pkgName, mRetrieveFlags); + ApplicationInfo info = mIpm.getApplicationInfo(pkgName, mRetrieveFlags, userId); + if (info == null) { + return; + } if (!info.enabled) { if (info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { @@ -784,20 +840,20 @@ public class ApplicationsState { } if (DEBUG_LOCKING) Log.v(TAG, "addPackage releasing lock"); } - } catch (NameNotFoundException e) { + } catch (RemoteException e) { } } - void removePackage(String pkgName) { + void removePackage(String pkgName, int userId) { synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "removePackage acquired lock"); - int idx = indexOfApplicationInfoLocked(pkgName); + int idx = indexOfApplicationInfoLocked(pkgName, userId); if (DEBUG) Log.i(TAG, "removePackage: " + pkgName + " @ " + idx); if (idx >= 0) { - AppEntry entry = mEntriesMap.get(pkgName); + AppEntry entry = mEntriesMap.get(userId).get(pkgName); if (DEBUG) Log.i(TAG, "removePackage: " + entry); if (entry != null) { - mEntriesMap.remove(pkgName); + mEntriesMap.get(userId).remove(pkgName); mAppEntries.remove(entry); } ApplicationInfo info = mApplications.get(idx); @@ -819,18 +875,53 @@ public class ApplicationsState { } } - void invalidatePackage(String pkgName) { - removePackage(pkgName); - addPackage(pkgName); + void invalidatePackage(String pkgName, int userId) { + removePackage(pkgName, userId); + addPackage(pkgName, userId); } - + + void addUser(int userId) { + if (mUm.getUserProfiles().contains(new UserHandle(userId))) { + synchronized (mEntriesMap) { + mEntriesMap.put(userId, new HashMap()); + if (mResumed) { + // If resumed, Manually pause, then cause a resume to repopulate the app list. + // This is the simplest way to reload the packages so that the new user + // is included. Otherwise the list will be repopulated on next resume. + doPauseLocked(); + doResumeIfNeededLocked(); + } + if (!mMainHandler.hasMessages(MainHandler.MSG_PACKAGE_LIST_CHANGED)) { + mMainHandler.sendEmptyMessage(MainHandler.MSG_PACKAGE_LIST_CHANGED); + } + } + } + } + + void removeUser(int userId) { + synchronized (mEntriesMap) { + HashMap userMap = mEntriesMap.get(userId); + if (userMap != null) { + for (AppEntry appEntry : userMap.values()) { + mAppEntries.remove(appEntry); + mApplications.remove(appEntry.info); + } + mEntriesMap.remove(userId); + if (!mMainHandler.hasMessages(MainHandler.MSG_PACKAGE_LIST_CHANGED)) { + mMainHandler.sendEmptyMessage(MainHandler.MSG_PACKAGE_LIST_CHANGED); + } + } + } + } + AppEntry getEntryLocked(ApplicationInfo info) { - AppEntry entry = mEntriesMap.get(info.packageName); + int userId = UserHandle.getUserId(info.uid); + AppEntry entry = mEntriesMap.get(userId).get(info.packageName); if (DEBUG) Log.i(TAG, "Looking up entry of pkg " + info.packageName + ": " + entry); if (entry == null) { if (DEBUG) Log.i(TAG, "Creating AppEntry for " + info.packageName); entry = new AppEntry(mContext, info, mCurId++); - mEntriesMap.put(info.packageName, entry); + mEntriesMap.get(userId).put(info.packageName, entry); mAppEntries.add(entry); } else if (entry.info != info) { entry.info = info; @@ -880,7 +971,12 @@ public class ApplicationsState { boolean sizeChanged = false; synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "onGetStatsCompleted acquired lock"); - AppEntry entry = mEntriesMap.get(stats.packageName); + HashMap userMap = mEntriesMap.get(stats.userHandle); + if (userMap == null) { + // The user must have been removed. + return; + } + AppEntry entry = userMap.get(stats.packageName); if (entry != null) { synchronized (entry) { entry.sizeStale = false; @@ -922,7 +1018,8 @@ public class ApplicationsState { } } if (mCurComputingSizePkg == null - || mCurComputingSizePkg.equals(stats.packageName)) { + || (mCurComputingSizePkg.equals(stats.packageName) + && mCurComputingSizeUserId == stats.userHandle)) { mCurComputingSizePkg = null; sendEmptyMessage(MSG_LOAD_SIZES); } @@ -966,7 +1063,8 @@ public class ApplicationsState { mMainHandler.sendMessage(m); } ApplicationInfo info = mApplications.get(i); - if (mEntriesMap.get(info.packageName) == null) { + int userId = UserHandle.getUserId(info.uid); + if (mEntriesMap.get(userId).get(info.packageName) == null) { numDone++; getEntryLocked(info); } @@ -1035,7 +1133,9 @@ public class ApplicationsState { } entry.sizeLoadStart = now; mCurComputingSizePkg = entry.info.packageName; - mPm.getPackageSizeInfo(mCurComputingSizePkg, mStatsObserver); + mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid); + mPm.getPackageSizeInfo(mCurComputingSizePkg, + mCurComputingSizeUserId, mStatsObserver); } if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES releasing: now computing"); return; diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java index d77d63f7f0b..59dbd0ee7c6 100755 --- a/src/com/android/settings/applications/InstalledAppDetails.java +++ b/src/com/android/settings/applications/InstalledAppDetails.java @@ -482,8 +482,9 @@ public class InstalledAppDetails extends AppInfoBase ActivityManager am = (ActivityManager)getActivity().getSystemService( Context.ACTIVITY_SERVICE); am.forceStopPackage(pkgName); - mState.invalidatePackage(pkgName); - ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName); + int userId = UserHandle.getUserId(mAppEntry.info.uid); + mState.invalidatePackage(pkgName, userId); + ApplicationsState.AppEntry newEnt = mState.getEntry(pkgName, userId); if (newEnt != null) { mAppEntry = newEnt; } diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java index 45431eb1990..01527552b56 100644 --- a/src/com/android/settings/applications/ManageApplications.java +++ b/src/com/android/settings/applications/ManageApplications.java @@ -35,6 +35,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.NetworkPolicyManager; +import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; @@ -70,13 +71,12 @@ import android.widget.Spinner; import com.android.internal.app.IMediaContainerService; import com.android.internal.content.PackageHelper; import com.android.settings.R; -import com.android.settings.SettingsActivity; -import com.android.settings.UserSpinnerAdapter; import com.android.settings.Settings.RunningServicesActivity; import com.android.settings.Settings.StorageUseActivity; +import com.android.settings.UserSpinnerAdapter; +import com.android.settings.Utils; import com.android.settings.applications.ApplicationsState.AppEntry; import com.android.settings.deviceinfo.StorageMeasurement; -import com.android.settings.Utils; import java.util.ArrayList; import java.util.Comparator; @@ -135,8 +135,7 @@ interface AppClickListener { * intent. */ public class ManageApplications extends Fragment implements - AppClickListener, DialogInterface.OnClickListener, - DialogInterface.OnDismissListener, OnItemSelectedListener { + AppClickListener, DialogInterface.OnClickListener, DialogInterface.OnDismissListener { static final String TAG = "ManageApplications"; static final boolean DEBUG = false; @@ -451,6 +450,7 @@ public class ManageApplications extends Fragment implements private LayoutInflater mInflater; private String mCurrentPkgName; + private int mCurrentUid; private Menu mOptionsMenu; @@ -472,7 +472,6 @@ public class ManageApplications extends Fragment implements private View mRootView; private ViewPager mViewPager; private ViewGroup mPinnedHeader; - private UserSpinnerAdapter mProfileSpinnerAdapter; private Spinner mSpinner; private Context mContext; @@ -911,9 +910,6 @@ public class ManageApplications extends Fragment implements mTabs.add(tab); mNumTabs = mTabs.size(); - - final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - mProfileSpinnerAdapter = Utils.createUserSpinnerAdapter(um, mContext); } @@ -926,14 +922,6 @@ public class ManageApplications extends Fragment implements container, false); mContentContainer = container; mRootView = rootView; - mPinnedHeader = (ViewGroup) mRootView.findViewById(R.id.pinned_header); - if (mProfileSpinnerAdapter != null) { - mSpinner = (Spinner) inflater.inflate(R.layout.spinner_view, null); - mSpinner.setAdapter(mProfileSpinnerAdapter); - mSpinner.setOnItemSelectedListener(this); - mPinnedHeader.addView(mSpinner); - mPinnedHeader.setVisibility(View.VISIBLE); - } mViewPager = (ViewPager) rootView.findViewById(R.id.pager); MyPagerAdapter adapter = new MyPagerAdapter(); mViewPager.setAdapter(adapter); @@ -1029,31 +1017,10 @@ public class ManageApplications extends Fragment implements @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) { - mApplicationsState.requestSize(mCurrentPkgName); + mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid)); } } - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - UserHandle selectedUser = mProfileSpinnerAdapter.getUserHandle(position); - if (selectedUser.getIdentifier() != UserHandle.myUserId()) { - Intent intent = new Intent(Settings.ACTION_APPLICATION_SETTINGS); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - int currentTab = mViewPager.getCurrentItem(); - intent.putExtra(EXTRA_LIST_TYPE, mTabs.get(currentTab).mListType); - mContext.startActivityAsUser(intent, selectedUser); - // Go back to default selection, which is the first one; this makes sure that pressing - // the back button takes you into a consistent state - mSpinner.setSelection(0); - } - } - - @Override - public void onNothingSelected(AdapterView parent) { - // Nothing to do - } - private void updateNumTabs() { int newNum = mApplicationsState.haveDisabledApps() ? mTabs.size() : (mTabs.size()-1); if (newNum != mNumTabs) { @@ -1076,13 +1043,13 @@ public class ManageApplications extends Fragment implements // utility method used to start sub activity private void startApplicationDetailsActivity() { - // start new fragment to display extended information - Bundle args = new Bundle(); - args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mCurrentPkgName); - - SettingsActivity sa = (SettingsActivity) getActivity(); - sa.startPreferencePanel(InstalledAppDetails.class.getName(), args, - R.string.application_info_label, null, this, INSTALLED_APP_DETAILS); + // TODO: Figure out if there is a way where we can spin up the profile's settings + // process ahead of time, to avoid a long load of data when user clicks on a managed app. + // Maybe when they load the list of apps that contains managed profile apps. + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.fromParts("package", mCurrentPkgName, null)); + getActivity().startActivityAsUser(intent, + new UserHandle(UserHandle.getUserId(mCurrentUid))); } @Override @@ -1273,6 +1240,7 @@ public class ManageApplications extends Fragment implements if (tab.mApplications != null && tab.mApplications.getCount() > position) { ApplicationsState.AppEntry entry = tab.mApplications.getAppEntry(position); mCurrentPkgName = entry.info.packageName; + mCurrentUid = entry.info.uid; startApplicationDetailsActivity(); } }