diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e3a7e969149..d1b09cb5f43 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4,6 +4,9 @@ coreApp="true" android:sharedUserId="android.uid.system"> + + diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index b7f62a300d7..21a5019f039 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -16,8 +16,6 @@ package com.android.settings; -import static android.content.Intent.EXTRA_USER; - import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerNative; @@ -70,8 +68,6 @@ import android.provider.ContactsContract.Data; import android.provider.ContactsContract.Profile; import android.provider.ContactsContract.RawContacts; import android.service.persistentdata.PersistentDataBlockManager; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; @@ -87,20 +83,21 @@ import android.widget.TabWidget; import com.android.internal.util.UserIcons; import com.android.settings.UserAdapter.UserDetails; -import com.android.settings.applications.ApplicationsState; import com.android.settings.dashboard.DashboardTile; import com.android.settings.drawable.CircleFramedDrawable; +import com.android.settingslib.applications.ApplicationsState; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.text.NumberFormat; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Locale; +import static android.content.Intent.EXTRA_USER; + public final class Utils { private static final String TAG = "Settings"; diff --git a/src/com/android/settings/applications/AdvancedAppSettings.java b/src/com/android/settings/applications/AdvancedAppSettings.java index f407cb15801..c2966fe6b0d 100644 --- a/src/com/android/settings/applications/AdvancedAppSettings.java +++ b/src/com/android/settings/applications/AdvancedAppSettings.java @@ -23,10 +23,11 @@ import android.preference.Preference; import com.android.internal.logging.MetricsLogger; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.applications.ApplicationsState.AppEntry; -import com.android.settings.applications.ApplicationsState.Session; import com.android.settings.applications.PermissionsSummaryHelper.PermissionsResultCallback; import com.android.settings.fuelgauge.PowerWhitelistBackend; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.applications.ApplicationsState.Session; import java.util.ArrayList; diff --git a/src/com/android/settings/applications/AppInfoBase.java b/src/com/android/settings/applications/AppInfoBase.java index 6dbeefd8b6d..ff618c2a200 100644 --- a/src/com/android/settings/applications/AppInfoBase.java +++ b/src/com/android/settings/applications/AppInfoBase.java @@ -38,7 +38,8 @@ import android.util.Log; import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; -import com.android.settings.applications.ApplicationsState.AppEntry; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; import java.util.ArrayList; diff --git a/src/com/android/settings/applications/AppPermissionSettings.java b/src/com/android/settings/applications/AppPermissionSettings.java deleted file mode 100644 index 16757d91545..00000000000 --- a/src/com/android/settings/applications/AppPermissionSettings.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.applications; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.os.Build; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AppSecurityPermissions; -import android.widget.ArrayAdapter; -import android.widget.LinearLayout; -import android.widget.Spinner; -import android.widget.TextView; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.telephony.ISms; -import com.android.internal.telephony.SmsUsageMonitor; -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.applications.ApplicationsState.AppEntry; - -import java.util.ArrayList; - -public class AppPermissionSettings extends AppInfoWithHeader { - - private ISms mSmsManager; - private View mRootView; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mSmsManager = ISms.Stub.asInterface(ServiceManager.getService("isms")); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - final View view = inflater.inflate(R.layout.permission_settings, container, false); - - final ViewGroup allDetails = (ViewGroup) view.findViewById(R.id.all_details); - Utils.forceCustomPadding(allDetails, true /* additive padding */); - - mRootView = view; - return view; - } - - @Override - protected boolean refreshUi() { - retrieveAppEntry(); - // Security permissions section - LinearLayout permsView = (LinearLayout) mRootView.findViewById(R.id.permissions_section); - AppSecurityPermissions asp = new AppSecurityPermissions(getActivity(), mPackageName); - int premiumSmsPermission = getPremiumSmsPermission(mPackageName); - // Premium SMS permission implies the app also has SEND_SMS permission, so the original - // application permissions list doesn't have to be shown/hidden separately. The premium - // SMS subsection should only be visible if the app has tried to send to a premium SMS. - if (asp.getPermissionCount() > 0 - || premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) { - permsView.setVisibility(View.VISIBLE); - } else { - permsView.setVisibility(View.GONE); - } - // Premium SMS permission subsection - TextView securityBillingDesc = (TextView) permsView.findViewById( - R.id.security_settings_billing_desc); - LinearLayout securityBillingList = (LinearLayout) permsView.findViewById( - R.id.security_settings_billing_list); - if (premiumSmsPermission != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) { - // Show the premium SMS permission selector - securityBillingDesc.setVisibility(View.VISIBLE); - securityBillingList.setVisibility(View.VISIBLE); - Spinner spinner = (Spinner) permsView.findViewById( - R.id.security_settings_premium_sms_list); - ArrayAdapter adapter = ArrayAdapter.createFromResource(getActivity(), - R.array.security_settings_premium_sms_values, - android.R.layout.simple_spinner_item); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinner.setAdapter(adapter); - // List items are in the same order as SmsUsageMonitor constants, offset by 1. - spinner.setSelection(premiumSmsPermission - 1); - spinner.setOnItemSelectedListener(new PremiumSmsSelectionListener( - mPackageName, mSmsManager)); - } else { - // Hide the premium SMS permission selector - securityBillingDesc.setVisibility(View.GONE); - securityBillingList.setVisibility(View.GONE); - } - // App permissions subsection - if (asp.getPermissionCount() > 0) { - // Make the security sections header visible - LinearLayout securityList = (LinearLayout) permsView.findViewById( - R.id.security_settings_list); - securityList.removeAllViews(); - securityList.addView(asp.getPermissionsViewWithRevokeButtons()); - // If this app is running under a shared user ID with other apps, - // update the description to explain this. - String[] packages = mPm.getPackagesForUid(mPackageInfo.applicationInfo.uid); - if (packages != null && packages.length > 1) { - ArrayList pnames = new ArrayList(); - for (int i=0; i 0) { - final Resources res = getActivity().getResources(); - String appListStr; - if (N == 1) { - appListStr = pnames.get(0).toString(); - } else if (N == 2) { - appListStr = res.getString(R.string.join_two_items, pnames.get(0), - pnames.get(1)); - } else { - appListStr = pnames.get(N-2).toString(); - for (int i=N-3; i>=0; i--) { - appListStr = res.getString(i == 0 ? R.string.join_many_items_first - : R.string.join_many_items_middle, pnames.get(i), appListStr); - } - appListStr = res.getString(R.string.join_many_items_last, - appListStr, pnames.get(N-1)); - } - TextView descr = (TextView) mRootView.findViewById( - R.id.security_settings_desc); - descr.setText(res.getString(R.string.security_settings_desc_multi, - mPackageInfo.applicationInfo.loadLabel(mPm), appListStr)); - } - } - } - return true; - } - - private int getPremiumSmsPermission(String packageName) { - try { - if (mSmsManager != null) { - return mSmsManager.getPremiumSmsPermission(packageName); - } - } catch (RemoteException ex) { - // ignored - } - return SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN; - } - - @Override - protected AlertDialog createDialog(int id, int errorCode) { - // No dialogs for Permissions screen. - return null; - } - - public static CharSequence getSummary(AppEntry appEntry, Context context) { - if (appEntry.info.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { - AppPermissions appPerms = new AppPermissions(context, appEntry.info.packageName); - int count = appPerms.getPermissionCount(); - int grantedCount = appPerms.getGrantedPermissionsCount(); - return context.getResources().getQuantityString(R.plurals.runtime_permissions_summary, - count, grantedCount, count); - } - AppSecurityPermissions asp = new AppSecurityPermissions(context, - appEntry.info.packageName); - int count = asp.getPermissionCount(); - return context.getResources().getQuantityString(R.plurals.permissions_summary, - count, count); - } - - @Override - protected int getMetricsCategory() { - return MetricsLogger.APPLICATIONS_APP_PERMISSION; - } - - private static class PremiumSmsSelectionListener implements AdapterView.OnItemSelectedListener { - private final String mPackageName; - private final ISms mSmsManager; - - PremiumSmsSelectionListener(String packageName, ISms smsManager) { - mPackageName = packageName; - mSmsManager = smsManager; - } - - @Override - public void onItemSelected(AdapterView parent, View view, int position, - long id) { - if (position >= 0 && position < 3) { - if (localLOGV) Log.d(TAG, "Selected premium SMS policy " + position); - setPremiumSmsPermission(mPackageName, (position + 1)); - } else { - Log.e(TAG, "Error: unknown premium SMS policy " + position); - } - } - - @Override - public void onNothingSelected(AdapterView parent) { - // Ignored - } - - private void setPremiumSmsPermission(String packageName, int permission) { - try { - if (mSmsManager != null) { - mSmsManager.setPremiumSmsPermission(packageName, permission); - } - } catch (RemoteException ex) { - // ignored - } - } - } - -} \ No newline at end of file diff --git a/src/com/android/settings/applications/AppStateBaseBridge.java b/src/com/android/settings/applications/AppStateBaseBridge.java index 04eb77bcf02..1e04e13cc21 100644 --- a/src/com/android/settings/applications/AppStateBaseBridge.java +++ b/src/com/android/settings/applications/AppStateBaseBridge.java @@ -19,8 +19,9 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; -import com.android.settings.applications.ApplicationsState.AppEntry; -import com.android.settings.applications.ApplicationsState.Session; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.applications.ApplicationsState.Session; import java.util.ArrayList; diff --git a/src/com/android/settings/applications/AppStateNotificationBridge.java b/src/com/android/settings/applications/AppStateNotificationBridge.java index 4ac86506794..5a8e811a9f2 100644 --- a/src/com/android/settings/applications/AppStateNotificationBridge.java +++ b/src/com/android/settings/applications/AppStateNotificationBridge.java @@ -17,10 +17,11 @@ package com.android.settings.applications; import android.content.pm.PackageManager; -import com.android.settings.applications.ApplicationsState.AppEntry; -import com.android.settings.applications.ApplicationsState.AppFilter; import com.android.settings.notification.NotificationBackend; import com.android.settings.notification.NotificationBackend.AppRow; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.applications.ApplicationsState.AppFilter; import java.util.ArrayList; diff --git a/src/com/android/settings/applications/AppStatePowerBridge.java b/src/com/android/settings/applications/AppStatePowerBridge.java index 40163cb2b2e..3b1707f8baf 100644 --- a/src/com/android/settings/applications/AppStatePowerBridge.java +++ b/src/com/android/settings/applications/AppStatePowerBridge.java @@ -15,9 +15,10 @@ */ package com.android.settings.applications; -import com.android.settings.applications.ApplicationsState.AppEntry; -import com.android.settings.applications.ApplicationsState.AppFilter; import com.android.settings.fuelgauge.PowerWhitelistBackend; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.applications.ApplicationsState.AppFilter; import java.util.ArrayList; diff --git a/src/com/android/settings/applications/AppStateUsageBridge.java b/src/com/android/settings/applications/AppStateUsageBridge.java index 22f19b23f17..c06492c0d09 100644 --- a/src/com/android/settings/applications/AppStateUsageBridge.java +++ b/src/com/android/settings/applications/AppStateUsageBridge.java @@ -30,8 +30,9 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; -import com.android.settings.applications.ApplicationsState.AppEntry; -import com.android.settings.applications.ApplicationsState.AppFilter; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.applications.ApplicationsState.AppFilter; import java.util.List; diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java index fe68cbc4e90..808f738e425 100644 --- a/src/com/android/settings/applications/AppStorageSettings.java +++ b/src/com/android/settings/applications/AppStorageSettings.java @@ -36,15 +36,15 @@ import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; -import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import com.android.settings.DropDownPreference; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.applications.ApplicationsState.AppEntry; -import com.android.settings.applications.ApplicationsState.Callbacks; import com.android.settings.deviceinfo.StorageWizardMoveConfirm; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.applications.ApplicationsState.Callbacks; import java.util.Collections; import java.util.List; diff --git a/src/com/android/settings/applications/AppViewHolder.java b/src/com/android/settings/applications/AppViewHolder.java index 34c99524532..f58cf067123 100644 --- a/src/com/android/settings/applications/AppViewHolder.java +++ b/src/com/android/settings/applications/AppViewHolder.java @@ -16,8 +16,6 @@ package com.android.settings.applications; -import com.android.settings.R; - import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -25,6 +23,9 @@ import android.widget.CheckBox; import android.widget.ImageView; import android.widget.TextView; +import com.android.settings.R; +import com.android.settingslib.applications.ApplicationsState; + // View Holder used when displaying views public class AppViewHolder { public ApplicationsState.AppEntry entry; diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java deleted file mode 100644 index 055e415ed21..00000000000 --- a/src/com/android/settings/applications/ApplicationsState.java +++ /dev/null @@ -1,1341 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.applications; - -import android.app.ActivityManager; -import android.app.AppGlobals; -import android.app.Application; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; -import android.content.pm.IPackageStatsObserver; -import android.content.pm.PackageManager; -import android.content.pm.PackageStats; -import android.content.pm.ParceledListSlice; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.UserHandle; -import android.os.UserManager; -import android.text.format.Formatter; -import android.util.Log; -import android.util.SparseArray; - -import java.io.File; -import java.text.Collator; -import java.text.Normalizer; -import java.text.Normalizer.Form; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Objects; -import java.util.regex.Pattern; - -/** - * Keeps track of information about all installed applications, lazy-loading - * as needed. - */ -public class ApplicationsState { - static final String TAG = "ApplicationsState"; - static final boolean DEBUG = false; - static final boolean DEBUG_LOCKING = false; - - public static interface Callbacks { - public void onRunningStateChanged(boolean running); - public void onPackageListChanged(); - public void onRebuildComplete(ArrayList apps); - public void onPackageIconChanged(); - public void onPackageSizeChanged(String packageName); - public void onAllSizesComputed(); - public void onLauncherInfoChanged(); - public void onLoadEntriesCompleted(); - } - - public static interface AppFilter { - public void init(); - public boolean filterApp(AppEntry info); - } - - static final int SIZE_UNKNOWN = -1; - static final int SIZE_INVALID = -2; - - static final Pattern REMOVE_DIACRITICALS_PATTERN - = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); - - public static String normalize(String str) { - String tmp = Normalizer.normalize(str, Form.NFD); - return REMOVE_DIACRITICALS_PATTERN.matcher(tmp) - .replaceAll("").toLowerCase(); - } - - public static class SizeInfo { - long cacheSize; - long codeSize; - long dataSize; - long externalCodeSize; - long externalDataSize; - - // This is the part of externalDataSize that is in the cache - // section of external storage. Note that we don't just combine - // this with cacheSize because currently the platform can't - // automatically trim this data when needed, so it is something - // the user may need to manage. The externalDataSize also includes - // this value, since what this is here is really the part of - // externalDataSize that we can just consider to be "cache" files - // for purposes of cleaning them up in the app details UI. - long externalCacheSize; - } - - public static class AppEntry extends SizeInfo { - final File apkFile; - final long id; - String label; - long size; - long internalSize; - long externalSize; - - boolean mounted; - - boolean hasLauncherEntry; - - String getNormalizedLabel() { - if (normalizedLabel != null) { - return normalizedLabel; - } - normalizedLabel = normalize(label); - return normalizedLabel; - } - - // Need to synchronize on 'this' for the following. - public ApplicationInfo info; - Drawable icon; - String sizeStr; - String internalSizeStr; - String externalSizeStr; - boolean sizeStale; - long sizeLoadStart; - - String normalizedLabel; - - // A location where extra info can be placed to be used by custom filters. - Object extraInfo; - - AppEntry(Context context, ApplicationInfo info, long id) { - apkFile = new File(info.sourceDir); - this.id = id; - this.info = info; - this.size = SIZE_UNKNOWN; - this.sizeStale = true; - ensureLabel(context); - } - - void ensureLabel(Context context) { - if (this.label == null || !this.mounted) { - if (!this.apkFile.exists()) { - this.mounted = false; - this.label = info.packageName; - } else { - this.mounted = true; - CharSequence label = info.loadLabel(context.getPackageManager()); - this.label = label != null ? label.toString() : info.packageName; - } - } - } - - boolean ensureIconLocked(Context context, PackageManager pm) { - if (this.icon == null) { - if (this.apkFile.exists()) { - this.icon = getBadgedIcon(pm); - return true; - } else { - this.mounted = false; - this.icon = context.getDrawable( - com.android.internal.R.drawable.sym_app_on_sd_unavailable_icon); - } - } else if (!this.mounted) { - // If the app wasn't mounted but is now mounted, reload - // its icon. - if (this.apkFile.exists()) { - this.mounted = true; - this.icon = getBadgedIcon(pm); - return true; - } - } - return false; - } - - private Drawable getBadgedIcon(PackageManager pm) { - // Do badging ourself so that it comes from the user of the app not the current user. - return pm.getUserBadgedIcon(pm.loadUnbadgedItemIcon(info, info), - new UserHandle(UserHandle.getUserId(info.uid))); - } - } - - public static final Comparator ALPHA_COMPARATOR = new Comparator() { - private final Collator sCollator = Collator.getInstance(); - @Override - public int compare(AppEntry object1, AppEntry object2) { - return sCollator.compare(object1.label, object2.label); - } - }; - - public static final Comparator SIZE_COMPARATOR - = new Comparator() { - private final Collator sCollator = Collator.getInstance(); - @Override - public int compare(AppEntry object1, AppEntry object2) { - if (object1.size < object2.size) return 1; - if (object1.size > object2.size) return -1; - return sCollator.compare(object1.label, object2.label); - } - }; - - public static final Comparator INTERNAL_SIZE_COMPARATOR - = new Comparator() { - private final Collator sCollator = Collator.getInstance(); - @Override - public int compare(AppEntry object1, AppEntry object2) { - if (object1.internalSize < object2.internalSize) return 1; - if (object1.internalSize > object2.internalSize) return -1; - return sCollator.compare(object1.label, object2.label); - } - }; - - public static final Comparator EXTERNAL_SIZE_COMPARATOR - = new Comparator() { - private final Collator sCollator = Collator.getInstance(); - @Override - public int compare(AppEntry object1, AppEntry object2) { - if (object1.externalSize < object2.externalSize) return 1; - if (object1.externalSize > object2.externalSize) return -1; - return sCollator.compare(object1.label, object2.label); - } - }; - - public static final AppFilter FILTER_PERSONAL = new AppFilter() { - private int mCurrentUser; - - public void init() { - mCurrentUser = ActivityManager.getCurrentUser(); - } - - @Override - public boolean filterApp(AppEntry entry) { - return UserHandle.getUserId(entry.info.uid) == mCurrentUser; - } - }; - - public static final AppFilter FILTER_WORK = new AppFilter() { - private int mCurrentUser; - - public void init() { - mCurrentUser = ActivityManager.getCurrentUser(); - } - - @Override - public boolean filterApp(AppEntry entry) { - return UserHandle.getUserId(entry.info.uid) != mCurrentUser; - } - }; - - public static final AppFilter FILTER_DOWNLOADED_AND_LAUNCHER = new AppFilter() { - public void init() { - } - - @Override - public boolean filterApp(AppEntry entry) { - if ((entry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { - return true; - } else if ((entry.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - return true; - } else if (entry.hasLauncherEntry) { - return true; - } - return false; - } - }; - - public static final AppFilter FILTER_THIRD_PARTY = new AppFilter() { - public void init() { - } - - @Override - public boolean filterApp(AppEntry entry) { - if ((entry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { - return true; - } else if ((entry.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - return true; - } - return false; - } - }; - - public static final AppFilter FILTER_DISABLED = new AppFilter() { - public void init() { - } - - @Override - public boolean filterApp(AppEntry entry) { - return !entry.info.enabled; - } - }; - - public static final AppFilter FILTER_ALL_ENABLED = new AppFilter() { - public void init() { - } - - @Override - public boolean filterApp(AppEntry entry) { - return entry.info.enabled; - } - }; - - public static final AppFilter FILTER_EVERYTHING = new AppFilter() { - public void init() { - } - - @Override - public boolean filterApp(AppEntry entry) { - return true; - } - }; - - public static final AppFilter FILTER_WITH_DOMAIN_URLS = new AppFilter() { - public void init() { - } - - @Override - public boolean filterApp(AppEntry entry) { - return (entry.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; - } - }; - - public static class VolumeFilter implements AppFilter { - private final String mVolumeUuid; - - public VolumeFilter(String volumeUuid) { - mVolumeUuid = volumeUuid; - } - - @Override - public void init() { - } - - @Override - public boolean filterApp(AppEntry info) { - return Objects.equals(info.info.volumeUuid, mVolumeUuid); - } - } - - public static class CompoundFilter implements AppFilter { - private final AppFilter mFirstFilter; - private final AppFilter mSecondFilter; - - public CompoundFilter(AppFilter first, AppFilter second) { - mFirstFilter = first; - mSecondFilter = second; - } - - @Override - public void init() { - mFirstFilter.init(); - mSecondFilter.init(); - } - - @Override - public boolean filterApp(AppEntry info) { - return mFirstFilter.filterApp(info) && mSecondFilter.filterApp(info); - } - } - - final Context mContext; - final PackageManager mPm; - final IPackageManager mIpm; - final UserManager mUm; - final int mOwnerRetrieveFlags; - final int mRetrieveFlags; - PackageIntentReceiver mPackageIntentReceiver; - - boolean mResumed; - boolean mHaveDisabledApps; - - // Information about all applications. Synchronize on mEntriesMap - // to protect access to these. - final ArrayList mSessions = new ArrayList(); - final ArrayList mRebuildingSessions = new ArrayList(); - final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges(); - // 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. - final ArrayList mActiveSessions = new ArrayList(); - - /** - * Receives notifications when applications are added/removed. - */ - private class PackageIntentReceiver extends BroadcastReceiver { - void registerReceiver() { - IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_CHANGED); - filter.addDataScheme("package"); - mContext.registerReceiver(this, filter); - // Register for events related to sdcard installation. - IntentFilter sdFilter = new IntentFilter(); - 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); - } - @Override - public void onReceive(Context context, Intent intent) { - String actionStr = intent.getAction(); - if (Intent.ACTION_PACKAGE_ADDED.equals(actionStr)) { - Uri data = intent.getData(); - String pkgName = data.getEncodedSchemeSpecificPart(); - 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(); - 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(); - 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 - // the SD card was inserted or ejected) we need to refresh the - // AppInfo with new label, icon and size information as appropriate - // given the newfound (un)availability of the application. - // A simple way to do that is to treat the refresh as a package - // removal followed by a package addition. - String pkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); - if (pkgList == null || pkgList.length == 0) { - // Ignore - return; - } - boolean avail = Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(actionStr); - if (avail) { - for (String pkgName : pkgList) { - 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)); - } - } - } - - void rebuildActiveSessions() { - synchronized (mEntriesMap) { - if (!mSessionsChanged) { - return; - } - mActiveSessions.clear(); - for (int i=0; i()); - } - mThread = new HandlerThread("ApplicationsState.Loader", - Process.THREAD_PRIORITY_BACKGROUND); - mThread.start(); - mBackgroundHandler = new BackgroundHandler(mThread.getLooper()); - - // Only the owner can see all apps. - mOwnerRetrieveFlags = PackageManager.GET_UNINSTALLED_PACKAGES | - PackageManager.GET_DISABLED_COMPONENTS | - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS; - mRetrieveFlags = PackageManager.GET_DISABLED_COMPONENTS | - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS; - - /** - * This is a trick to prevent the foreground thread from being delayed. - * The problem is that Dalvik monitors are initially spin locks, to keep - * them lightweight. This leads to unfair contention -- Even though the - * background thread only holds the lock for a short amount of time, if - * it keeps running and locking again it can prevent the main thread from - * acquiring its lock for a long time... sometimes even > 5 seconds - * (leading to an ANR). - * - * Dalvik will promote a monitor to a "real" lock if it detects enough - * contention on it. It doesn't figure this out fast enough for us - * here, though, so this little trick will force it to turn into a real - * lock immediately. - */ - synchronized (mEntriesMap) { - try { - mEntriesMap.wait(1); - } catch (InterruptedException e) { - } - } - } - - Looper getBackgroundLooper() { - return mThread.getLooper(); - } - - public class Session { - final Callbacks mCallbacks; - boolean mResumed; - - // Rebuilding of app list. Synchronized on mRebuildSync. - final Object mRebuildSync = new Object(); - boolean mRebuildRequested; - boolean mRebuildAsync; - AppFilter mRebuildFilter; - Comparator mRebuildComparator; - ArrayList mRebuildResult; - ArrayList mLastAppList; - - Session(Callbacks callbacks) { - mCallbacks = callbacks; - } - - public void resume() { - if (DEBUG_LOCKING) Log.v(TAG, "resume about to acquire lock..."); - synchronized (mEntriesMap) { - if (!mResumed) { - mResumed = true; - mSessionsChanged = true; - doResumeIfNeededLocked(); - } - } - if (DEBUG_LOCKING) Log.v(TAG, "...resume releasing lock"); - } - - public void pause() { - if (DEBUG_LOCKING) Log.v(TAG, "pause about to acquire lock..."); - synchronized (mEntriesMap) { - if (mResumed) { - mResumed = false; - mSessionsChanged = true; - mBackgroundHandler.removeMessages(BackgroundHandler.MSG_REBUILD_LIST, this); - doPauseIfNeededLocked(); - } - if (DEBUG_LOCKING) Log.v(TAG, "...pause releasing lock"); - } - } - - ArrayList getAllApps() { - synchronized (mEntriesMap) { - return new ArrayList<>(mAppEntries); - } - } - - // Creates a new list of app entries with the given filter and comparator. - ArrayList rebuild(AppFilter filter, Comparator comparator) { - synchronized (mRebuildSync) { - synchronized (mEntriesMap) { - mRebuildingSessions.add(this); - mRebuildRequested = true; - mRebuildAsync = false; - mRebuildFilter = filter; - mRebuildComparator = comparator; - mRebuildResult = null; - if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_REBUILD_LIST)) { - Message msg = mBackgroundHandler.obtainMessage( - BackgroundHandler.MSG_REBUILD_LIST); - mBackgroundHandler.sendMessage(msg); - } - } - - // We will wait for .25s for the list to be built. - long waitend = SystemClock.uptimeMillis()+250; - - while (mRebuildResult == null) { - long now = SystemClock.uptimeMillis(); - if (now >= waitend) { - break; - } - try { - mRebuildSync.wait(waitend - now); - } catch (InterruptedException e) { - } - } - - mRebuildAsync = true; - - return mRebuildResult; - } - } - - void handleRebuildList() { - AppFilter filter; - Comparator comparator; - synchronized (mRebuildSync) { - if (!mRebuildRequested) { - return; - } - - filter = mRebuildFilter; - comparator = mRebuildComparator; - mRebuildRequested = false; - mRebuildFilter = null; - mRebuildComparator = null; - } - - Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); - - if (filter != null) { - filter.init(); - } - - List apps; - synchronized (mEntriesMap) { - apps = new ArrayList<>(mAppEntries); - } - - ArrayList filteredApps = new ArrayList(); - if (DEBUG) Log.i(TAG, "Rebuilding..."); - for (int i=0; i(); - for (UserHandle user : mUm.getUserProfiles()) { - try { - // If this user is new, it needs a map created. - if (mEntriesMap.indexOfKey(user.getIdentifier()) < 0) { - mEntriesMap.put(user.getIdentifier(), new HashMap()); - } - ParceledListSlice list = - mIpm.getInstalledApplications( - user.isOwner() ? mOwnerRetrieveFlags : 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. - clearEntries(); - } else { - for (int i=0; i mApplications.size()) { - // There are less apps now, some must have been uninstalled. - clearEntries(); - } - mCurComputingSizePkg = null; - if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_LOAD_ENTRIES)) { - mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ENTRIES); - } - } - - private void clearEntries() { - for (int i = 0; i < mEntriesMap.size(); i++) { - mEntriesMap.valueAt(i).clear(); - } - mAppEntries.clear(); - } - - public boolean haveDisabledApps() { - return mHaveDisabledApps; - } - - void doPauseIfNeededLocked() { - if (!mResumed) { - return; - } - for (int i=0; i sumCacheSizes now has lock"); - for (int i=mAppEntries.size()-1; i>=0; i--) { - sum += mAppEntries.get(i).cacheSize; - } - if (DEBUG_LOCKING) Log.v(TAG, "...sumCacheSizes releasing lock"); - } - return sum; - } - - int indexOfApplicationInfoLocked(String pkgName, int userId) { - for (int i=mApplications.size()-1; i>=0; i--) { - ApplicationInfo appInfo = mApplications.get(i); - if (appInfo.packageName.equals(pkgName) - && UserHandle.getUserId(appInfo.uid) == userId) { - return i; - } - } - return -1; - } - - void addPackage(String pkgName, int userId) { - try { - synchronized (mEntriesMap) { - if (DEBUG_LOCKING) Log.v(TAG, "addPackage acquired lock"); - if (DEBUG) Log.i(TAG, "Adding package " + pkgName); - if (!mResumed) { - // If we are not resumed, we will do a full query the - // next time we resume, so there is no reason to do work - // here. - if (DEBUG_LOCKING) Log.v(TAG, "addPackage release lock: not resumed"); - return; - } - 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 = mIpm.getApplicationInfo(pkgName, - userId == UserHandle.USER_OWNER ? mOwnerRetrieveFlags : mRetrieveFlags, - userId); - if (info == null) { - return; - } - if (!info.enabled) { - if (info.enabledSetting - != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { - return; - } - mHaveDisabledApps = true; - } - mApplications.add(info); - if (!mBackgroundHandler.hasMessages(BackgroundHandler.MSG_LOAD_ENTRIES)) { - mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ENTRIES); - } - if (!mMainHandler.hasMessages(MainHandler.MSG_PACKAGE_LIST_CHANGED)) { - mMainHandler.sendEmptyMessage(MainHandler.MSG_PACKAGE_LIST_CHANGED); - } - if (DEBUG_LOCKING) Log.v(TAG, "addPackage releasing lock"); - } - } catch (RemoteException e) { - } - } - - void removePackage(String pkgName, int userId) { - synchronized (mEntriesMap) { - if (DEBUG_LOCKING) Log.v(TAG, "removePackage acquired lock"); - int idx = indexOfApplicationInfoLocked(pkgName, userId); - if (DEBUG) Log.i(TAG, "removePackage: " + pkgName + " @ " + idx); - if (idx >= 0) { - AppEntry entry = mEntriesMap.get(userId).get(pkgName); - if (DEBUG) Log.i(TAG, "removePackage: " + entry); - if (entry != null) { - mEntriesMap.get(userId).remove(pkgName); - mAppEntries.remove(entry); - } - ApplicationInfo info = mApplications.get(idx); - mApplications.remove(idx); - if (!info.enabled) { - mHaveDisabledApps = false; - for (int i=0; i()); - 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) { - 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.get(userId).put(info.packageName, entry); - mAppEntries.add(entry); - } else if (entry.info != info) { - entry.info = info; - } - return entry; - } - - // -------------------------------------------------------------- - - private long getTotalInternalSize(PackageStats ps) { - if (ps != null) { - return ps.codeSize + ps.dataSize; - } - return SIZE_INVALID; - } - - private long getTotalExternalSize(PackageStats ps) { - if (ps != null) { - // We also include the cache size here because for non-emulated - // we don't automtically clean cache files. - return ps.externalCodeSize + ps.externalDataSize - + ps.externalCacheSize - + ps.externalMediaSize + ps.externalObbSize; - } - return SIZE_INVALID; - } - - private String getSizeStr(long size) { - if (size >= 0) { - return Formatter.formatFileSize(mContext, size); - } - return null; - } - - final HandlerThread mThread; - final BackgroundHandler mBackgroundHandler; - class BackgroundHandler extends Handler { - static final int MSG_REBUILD_LIST = 1; - static final int MSG_LOAD_ENTRIES = 2; - static final int MSG_LOAD_ICONS = 3; - static final int MSG_LOAD_SIZES = 4; - static final int MSG_LOAD_LAUNCHER = 5; - - boolean mRunning; - - final IPackageStatsObserver.Stub mStatsObserver = new IPackageStatsObserver.Stub() { - public void onGetStatsCompleted(PackageStats stats, boolean succeeded) { - boolean sizeChanged = false; - synchronized (mEntriesMap) { - if (DEBUG_LOCKING) Log.v(TAG, "onGetStatsCompleted acquired lock"); - 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; - entry.sizeLoadStart = 0; - long externalCodeSize = stats.externalCodeSize - + stats.externalObbSize; - long externalDataSize = stats.externalDataSize - + stats.externalMediaSize; - long newSize = externalCodeSize + externalDataSize - + getTotalInternalSize(stats); - if (entry.size != newSize || - entry.cacheSize != stats.cacheSize || - entry.codeSize != stats.codeSize || - entry.dataSize != stats.dataSize || - entry.externalCodeSize != externalCodeSize || - entry.externalDataSize != externalDataSize || - entry.externalCacheSize != stats.externalCacheSize) { - entry.size = newSize; - entry.cacheSize = stats.cacheSize; - entry.codeSize = stats.codeSize; - entry.dataSize = stats.dataSize; - entry.externalCodeSize = externalCodeSize; - entry.externalDataSize = externalDataSize; - entry.externalCacheSize = stats.externalCacheSize; - entry.sizeStr = getSizeStr(entry.size); - entry.internalSize = getTotalInternalSize(stats); - entry.internalSizeStr = getSizeStr(entry.internalSize); - entry.externalSize = getTotalExternalSize(stats); - entry.externalSizeStr = getSizeStr(entry.externalSize); - if (DEBUG) Log.i(TAG, "Set size of " + entry.label + " " + entry - + ": " + entry.sizeStr); - sizeChanged = true; - } - } - if (sizeChanged) { - Message msg = mMainHandler.obtainMessage( - MainHandler.MSG_PACKAGE_SIZE_CHANGED, stats.packageName); - mMainHandler.sendMessage(msg); - } - } - if (mCurComputingSizePkg != null - && (mCurComputingSizePkg.equals(stats.packageName) - && mCurComputingSizeUserId == stats.userHandle)) { - mCurComputingSizePkg = null; - sendEmptyMessage(MSG_LOAD_SIZES); - } - if (DEBUG_LOCKING) Log.v(TAG, "onGetStatsCompleted releasing lock"); - } - } - }; - - BackgroundHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - // Always try rebuilding list first thing, if needed. - ArrayList rebuildingSessions = null; - synchronized (mEntriesMap) { - if (mRebuildingSessions.size() > 0) { - rebuildingSessions = new ArrayList(mRebuildingSessions); - mRebuildingSessions.clear(); - } - } - if (rebuildingSessions != null) { - for (int i=0; i= 6) { - sendEmptyMessage(MSG_LOAD_ENTRIES); - } else { - if (!mMainHandler.hasMessages(MainHandler.MSG_LOAD_ENTRIES_COMPLETE)) { - mMainHandler.sendEmptyMessage(MainHandler.MSG_LOAD_ENTRIES_COMPLETE); - } - sendEmptyMessage(MSG_LOAD_LAUNCHER); - } - } break; - case MSG_LOAD_LAUNCHER: { - Intent launchIntent = new Intent(Intent.ACTION_MAIN, null) - .addCategory(Intent.CATEGORY_LAUNCHER); - - for (int i = 0; i < mEntriesMap.size(); i++) { - int userId = mEntriesMap.keyAt(i); - List intents = mPm.queryIntentActivitiesAsUser(launchIntent, - PackageManager.GET_DISABLED_COMPONENTS, userId); - synchronized (mEntriesMap) { - if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_LAUNCHER acquired lock"); - HashMap userEntries = mEntriesMap.valueAt(i); - final int N = intents.size(); - for (int j = 0; j < N; j++) { - String packageName = intents.get(j).activityInfo.packageName; - AppEntry entry = userEntries.get(packageName); - if (entry != null) { - entry.hasLauncherEntry = true; - } else { - Log.w(TAG, "Cannot find pkg: " + packageName - + " on user " + userId); - } - } - if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_LAUNCHER releasing lock"); - } - } - - if (!mMainHandler.hasMessages(MainHandler.MSG_LAUNCHER_INFO_CHANGED)) { - mMainHandler.sendEmptyMessage(MainHandler.MSG_LAUNCHER_INFO_CHANGED); - } - sendEmptyMessage(MSG_LOAD_ICONS); - } break; - case MSG_LOAD_ICONS: { - int numDone = 0; - synchronized (mEntriesMap) { - if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_ICONS acquired lock"); - for (int i=0; i 0) { - if (!mMainHandler.hasMessages(MainHandler.MSG_PACKAGE_ICON_CHANGED)) { - mMainHandler.sendEmptyMessage(MainHandler.MSG_PACKAGE_ICON_CHANGED); - } - } - if (numDone >= 2) { - sendEmptyMessage(MSG_LOAD_ICONS); - } else { - sendEmptyMessage(MSG_LOAD_SIZES); - } - } break; - case MSG_LOAD_SIZES: { - synchronized (mEntriesMap) { - if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES acquired lock"); - if (mCurComputingSizePkg != null) { - if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES releasing: currently computing"); - return; - } - - long now = SystemClock.uptimeMillis(); - for (int i=0; i