diff options
-rw-r--r-- | AndroidManifest.xml | 14 | ||||
-rw-r--r-- | res/drawable/ic_settings_24dp.xml | 25 | ||||
-rw-r--r-- | res/layout/apps_filter_spinner.xml | 41 | ||||
-rw-r--r-- | res/layout/filter_spinner_item.xml | 27 | ||||
-rw-r--r-- | res/layout/manage_applications_content.xml | 43 | ||||
-rw-r--r-- | res/menu/manage_apps.xml | 23 | ||||
-rw-r--r-- | res/values/strings.xml | 29 | ||||
-rw-r--r-- | res/xml/advanced_apps.xml | 38 | ||||
-rw-r--r-- | src/com/android/settings/Settings.java | 1 | ||||
-rw-r--r-- | src/com/android/settings/applications/AdvancedAppSettings.java | 257 | ||||
-rw-r--r-- | src/com/android/settings/applications/AppInfoBase.java | 5 | ||||
-rw-r--r-- | src/com/android/settings/applications/ApplicationsState.java | 184 | ||||
-rw-r--r-- | src/com/android/settings/applications/ManageApplications.java | 1252 | ||||
-rw-r--r-- | src/com/android/settings/search/Ranking.java | 25 | ||||
-rw-r--r-- | src/com/android/settings/search/SearchIndexableResources.java | 8 |
15 files changed, 997 insertions, 975 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8eccf9e..883ded3 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -759,7 +759,6 @@ <intent-filter android:priority="1"> <action android:name="android.settings.APPLICATION_SETTINGS" /> <action android:name="android.settings.MANAGE_APPLICATIONS_SETTINGS" /> - <action android:name="android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <intent-filter> @@ -774,6 +773,19 @@ android:resource="@id/application_settings" /> </activity> + <activity android:name="Settings$AllApplicationsActivity" + android:label="@string/applications_settings" + android:taskAffinity=""> + <intent-filter> + <action android:name="android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <meta-data android:name="com.android.settings.FRAGMENT_CLASS" + android:value="com.android.settings.applications.ManageApplications" /> + <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID" + android:resource="@id/application_settings" /> + </activity> + <!-- Keep compatibility with old shortcuts. --> <activity-alias android:name=".applications.ManageApplications" android:label="@string/applications_settings" diff --git a/res/drawable/ic_settings_24dp.xml b/res/drawable/ic_settings_24dp.xml new file mode 100644 index 0000000..545bc2d --- /dev/null +++ b/res/drawable/ic_settings_24dp.xml @@ -0,0 +1,25 @@ +<!-- + 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. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z" + android:fillColor="#ffffffff" /> +</vector> diff --git a/res/layout/apps_filter_spinner.xml b/res/layout/apps_filter_spinner.xml new file mode 100644 index 0000000..f72d7ee --- /dev/null +++ b/res/layout/apps_filter_spinner.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:background="@drawable/switchbar_background" + android:gravity="center_vertical" + android:theme="?attr/switchBarTheme" > + + <Spinner + android:id="@+id/filter_spinner" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:layout_marginStart="@dimen/switchbar_subsettings_margin_start" + android:layout_alignWithParentIfMissing="true" + android:layout_centerVertical="true" + android:textAlignment="viewStart" /> + + <View + android:id="@+id/row_divider" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:attr/listDivider" /> + +</RelativeLayout> + diff --git a/res/layout/filter_spinner_item.xml b/res/layout/filter_spinner_item.xml new file mode 100644 index 0000000..e83dd80 --- /dev/null +++ b/res/layout/filter_spinner_item.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/text1" + style="?android:attr/spinnerItemStyle" + android:singleLine="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:textAppearance="@style/TextAppearance.Switch" + android:textColor="@android:color/white" + android:textAlignment="inherit"/> diff --git a/res/layout/manage_applications_content.xml b/res/layout/manage_applications_content.xml deleted file mode 100644 index 364a002..0000000 --- a/res/layout/manage_applications_content.xml +++ /dev/null @@ -1,43 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2012, 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. -*/ ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:background="@drawable/default_preference_background"> - - <android.support.v4.view.ViewPager - android:id="@+id/pager" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1"> - <android.support.v4.view.PagerTabStrip - android:id="@+id/tabs" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:textAppearance="@style/TextAppearance.PagerTabs" - android:padding="0dp"> - </android.support.v4.view.PagerTabStrip> - </android.support.v4.view.ViewPager> - -</LinearLayout> diff --git a/res/menu/manage_apps.xml b/res/menu/manage_apps.xml new file mode 100644 index 0000000..577e981 --- /dev/null +++ b/res/menu/manage_apps.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/advanced" + android:title="@string/advanced_apps" + android:icon="@drawable/ic_settings_24dp" + android:showAsAction="collapseActionView|ifRoom" /> +</menu> diff --git a/res/values/strings.xml b/res/values/strings.xml index c202a89..be27f83 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5626,6 +5626,8 @@ <string name="keywords_accounts">account</string> <string name="keywords_users">restriction restrict restricted</string> <string name="keywords_keyboard_and_ime">text correction correct sound vibrate auto language gesture suggest suggestion theme offensive word type emoji international</string> + <string name="keywords_reset_apps">reset preferences default</string> + <string name="keywords_all_apps">apps download applications system</string> <!-- Search keywords for different screen unlock modes : slide to unlock, password, pattern and PIN [CHAR LIMIT=none] --> <string name="keywords_lockscreen">slide password pattern pin</string> @@ -6088,10 +6090,29 @@ <item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> permissions granted</item> </plurals> - <!-- Launch defaults preference summary with some set [CHAR LIMIT=40] --> - <string name="launch_defaults_some">Some defaults set</string> - <!-- Launch defaults preference summary with none set [CHAR LIMIT=40] --> - <string name="launch_defaults_none">No defaults set</string> + <!-- Launch defaults preference summary with some set [CHAR LIMIT=40] --> + <string name="launch_defaults_some">Some defaults set</string> + <!-- Launch defaults preference summary with none set [CHAR LIMIT=40] --> + <string name="launch_defaults_none">No defaults set</string> + + <!-- Label for showing all apps in list [CHAR LIMIT=30] --> + <string name="filter_all_apps">All apps</string> + <!-- Label for showing enabled apps in list [CHAR LIMIT=30] --> + <string name="filter_enabled_apps">Enabled</string> + <!-- Label for showing personal apps in list [CHAR LIMIT=30] --> + <string name="filter_personal_apps">Personal</string> + <!-- Label for showing work apps in list [CHAR LIMIT=30] --> + <string name="filter_work_apps">Work</string> + + <!-- Description for advanced menu option to reset app preferences [CHAR LIMIT=NONE] --> + <string name="reset_app_preferences_description">Reset preferences across all apps to defaults</string> + + <!-- Description of settings item that leads to list of all apps + [CHAR LIMIT=NONE] --> + <string name="all_apps_summary"><xliff:g id="count" example="10">%d</xliff:g> apps installed, including system and downloaded apps</string> + + <!-- Title for advanced application management settings [CHAR LIMIT=30] --> + <string name="advanced_apps">Advanced</string> <!-- Warning toast shown when data usage screen can't find specified app --> <string name="unknown_app">Unknown app</string> diff --git a/res/xml/advanced_apps.xml b/res/xml/advanced_apps.xml new file mode 100644 index 0000000..a6cec13 --- /dev/null +++ b/res/xml/advanced_apps.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:settings="http://schemas.android.com/apk/res/com.android.settings" + android:key="applications_settings"> + + <PreferenceScreen + android:key="all_apps" + android:fragment="com.android.settings.applications.ManageApplications" + android:title="@string/filter_all_apps" + settings:keywords="@string/keywords_all_apps"> + <extra + android:name="classname" + android:value="com.android.settings.Settings$AllApplicationsActivity" /> + </PreferenceScreen> + + <Preference + android:key="reset_all" + android:title="@string/reset_app_preferences" + android:summary="@string/reset_app_preferences_description" + settings:keywords="@string/keywords_reset_apps" /> + +</PreferenceScreen> diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index b16fe81..20ce116 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -47,6 +47,7 @@ public class Settings extends SettingsActivity { public static class DeviceInfoSettingsActivity extends SettingsActivity { /* empty */ } public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ } public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ } + public static class AllApplicationsActivity extends SettingsActivity { /* empty */ } public static class AppOpsSummaryActivity extends SettingsActivity { @Override public boolean isValidFragment(String className) { diff --git a/src/com/android/settings/applications/AdvancedAppSettings.java b/src/com/android/settings/applications/AdvancedAppSettings.java new file mode 100644 index 0000000..6692d6b --- /dev/null +++ b/src/com/android/settings/applications/AdvancedAppSettings.java @@ -0,0 +1,257 @@ +/* + * 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 static android.net.NetworkPolicyManager.POLICY_NONE; +import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; + +import android.app.ActivityManager; +import android.app.AlertDialog; +import android.app.AppOpsManager; +import android.app.INotificationManager; +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.net.NetworkPolicyManager; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.applications.ApplicationsState.AppEntry; +import com.android.settings.applications.ApplicationsState.Callbacks; +import com.android.settings.applications.ApplicationsState.Session; + +import java.util.ArrayList; +import java.util.List; + +public class AdvancedAppSettings extends SettingsPreferenceFragment implements Callbacks, + DialogInterface.OnClickListener, DialogInterface.OnDismissListener { + + static final String TAG = "AdvancedAppSettings"; + static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private static final String KEY_ALL_APPS = "all_apps"; + private static final String KEY_RESET_ALL = "reset_all"; + private static final String EXTRA_RESET_DIALOG = "resetDialog"; + + private ApplicationsState mApplicationsState; + private Session mSession; + private Preference mAllApps; + private Preference mResetAll; + + AlertDialog mResetDialog; + + private boolean mActivityResumed; + private PackageManager mPm; + private IPackageManager mIPm; + private INotificationManager mNm; + private NetworkPolicyManager mNpm; + private AppOpsManager mAom; + private Handler mHandler; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + addPreferencesFromResource(R.xml.advanced_apps); + + mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication()); + mSession = mApplicationsState.newSession(this); + + mAllApps = findPreference(KEY_ALL_APPS); + mResetAll = findPreference(KEY_RESET_ALL); + mResetAll.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + buildResetDialog(); + return true; + } + }); + updateAllAppsSummary(); + + mPm = getActivity().getPackageManager(); + mIPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + mNm = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + mNpm = NetworkPolicyManager.from(getActivity()); + mAom = (AppOpsManager)getActivity().getSystemService(Context.APP_OPS_SERVICE); + mHandler = new Handler(getActivity().getMainLooper()); + } + + private void updateAllAppsSummary() { + mAllApps.setSummary(getString(R.string.all_apps_summary, mSession.getAllApps().size())); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) { + buildResetDialog(); + } + + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override + public void onStop() { + super.onStop(); + if (mResetDialog != null) { + mResetDialog.dismiss(); + mResetDialog = null; + } + } + + @Override + public void onResume() { + super.onResume(); + mActivityResumed = true; + } + + @Override + public void onPause() { + mActivityResumed = false; + super.onPause(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (mResetDialog != null) { + outState.putBoolean(EXTRA_RESET_DIALOG, true); + } + } + + void buildResetDialog() { + if (mResetDialog == null) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.reset_app_preferences_title); + builder.setMessage(R.string.reset_app_preferences_desc); + builder.setPositiveButton(R.string.reset_app_preferences_button, this); + builder.setNegativeButton(R.string.cancel, null); + mResetDialog = builder.show(); + mResetDialog.setOnDismissListener(this); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + if (mResetDialog == dialog) { + mResetDialog = null; + } + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (mResetDialog == dialog) { + (new AsyncTask<Void, Void, Void>() { + @Override protected Void doInBackground(Void... params) { + List<ApplicationInfo> apps = mPm.getInstalledApplications( + PackageManager.GET_DISABLED_COMPONENTS); + for (int i=0; i<apps.size(); i++) { + ApplicationInfo app = apps.get(i); + try { + if (DEBUG) Log.v(TAG, "Enabling notifications: " + app.packageName); + mNm.setNotificationsEnabledForPackage(app.packageName, app.uid, true); + } catch (android.os.RemoteException ex) { + } + if (!app.enabled) { + if (DEBUG) Log.v(TAG, "Enabling app: " + app.packageName); + if (mPm.getApplicationEnabledSetting(app.packageName) + == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + mPm.setApplicationEnabledSetting(app.packageName, + PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, + PackageManager.DONT_KILL_APP); + } + } + } + try { + mIPm.resetPreferredActivities(UserHandle.myUserId()); + } catch (RemoteException e) { + } + mAom.resetAllModes(); + final int[] restrictedUids = mNpm.getUidsWithPolicy( + POLICY_REJECT_METERED_BACKGROUND); + final int currentUserId = ActivityManager.getCurrentUser(); + for (int uid : restrictedUids) { + // Only reset for current user + if (UserHandle.getUserId(uid) == currentUserId) { + if (DEBUG) Log.v(TAG, "Clearing data policy: " + uid); + mNpm.setUidPolicy(uid, POLICY_NONE); + } + } + mHandler.post(new Runnable() { + @Override public void run() { + if (DEBUG) Log.v(TAG, "Done clearing"); + if (getActivity() != null && mActivityResumed) { + if (DEBUG) Log.v(TAG, "Updating UI!"); + + } + } + }); + return null; + } + }).execute(); + } + } + + @Override + public void onRunningStateChanged(boolean running) { + // No-op. + } + + @Override + public void onPackageListChanged() { + updateAllAppsSummary(); + } + + @Override + public void onRebuildComplete(ArrayList<AppEntry> apps) { + // No-op. + } + + @Override + public void onPackageIconChanged() { + // No-op. + } + + @Override + public void onPackageSizeChanged(String packageName) { + // No-op. + } + + @Override + public void onAllSizesComputed() { + // No-op. + } + + @Override + public void onLauncherInfoChanged() { + // No-op. + } + +} diff --git a/src/com/android/settings/applications/AppInfoBase.java b/src/com/android/settings/applications/AppInfoBase.java index 28f2925..b438051 100644 --- a/src/com/android/settings/applications/AppInfoBase.java +++ b/src/com/android/settings/applications/AppInfoBase.java @@ -180,6 +180,11 @@ public abstract class AppInfoBase extends PreferenceFragment } @Override + public void onLauncherInfoChanged() { + // No op. + } + + @Override public void onPackageListChanged() { refreshUi(); } diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java index 3825296..51a15cf 100644 --- a/src/com/android/settings/applications/ApplicationsState.java +++ b/src/com/android/settings/applications/ApplicationsState.java @@ -1,5 +1,6 @@ package com.android.settings.applications; +import android.app.ActivityManager; import android.app.AppGlobals; import android.app.Application; import android.content.BroadcastReceiver; @@ -12,6 +13,7 @@ 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; @@ -54,11 +56,12 @@ public class ApplicationsState { public void onPackageIconChanged(); public void onPackageSizeChanged(String packageName); public void onAllSizesComputed(); + public void onLauncherInfoChanged(); } public static interface AppFilter { public void init(); - public boolean filterApp(ApplicationInfo info); + public boolean filterApp(AppEntry info); } static final int SIZE_UNKNOWN = -1; @@ -90,7 +93,7 @@ public class ApplicationsState { // 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; @@ -100,7 +103,9 @@ public class ApplicationsState { long externalSize; boolean mounted; - + + boolean hasLauncherEntry; + String getNormalizedLabel() { if (normalizedLabel != null) { return normalizedLabel; @@ -128,7 +133,7 @@ public class ApplicationsState { this.sizeStale = true; ensureLabel(context); } - + void ensureLabel(Context context) { if (this.label == null || !this.mounted) { if (!this.apkFile.exists()) { @@ -141,7 +146,7 @@ public class ApplicationsState { } } } - + boolean ensureIconLocked(Context context, PackageManager pm) { if (this.icon == null) { if (this.apkFile.exists()) { @@ -175,13 +180,6 @@ public class ApplicationsState { private final Collator sCollator = Collator.getInstance(); @Override public int compare(AppEntry object1, AppEntry object2) { - final boolean normal1 = object1.info.enabled - && (object1.info.flags&ApplicationInfo.FLAG_INSTALLED) != 0; - final boolean normal2 = object2.info.enabled - && (object2.info.flags&ApplicationInfo.FLAG_INSTALLED) != 0; - if (normal1 != normal2) { - return normal1 ? -1 : 1; - } return sCollator.compare(object1.label, object2.label); } }; @@ -219,58 +217,105 @@ public class ApplicationsState { } }; - public static final AppFilter THIRD_PARTY_FILTER = new AppFilter() { + 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(ApplicationInfo info) { - if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + public boolean filterApp(AppEntry entry) { + if ((entry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { return true; - } else if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + } else if ((entry.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { return true; } return false; } }; - public static final AppFilter ON_SD_CARD_FILTER = new AppFilter() { + public static final AppFilter FILTER_ON_SD_CARD = new AppFilter() { final CanBeOnSdCardChecker mCanBeOnSdCardChecker = new CanBeOnSdCardChecker(); - + public void init() { mCanBeOnSdCardChecker.init(); } - + @Override - public boolean filterApp(ApplicationInfo info) { - return mCanBeOnSdCardChecker.check(info); + public boolean filterApp(AppEntry entry) { + return mCanBeOnSdCardChecker.check(entry.info); } }; - public static final AppFilter DISABLED_FILTER = new AppFilter() { + public static final AppFilter FILTER_DISABLED = new AppFilter() { public void init() { } - + @Override - public boolean filterApp(ApplicationInfo info) { - if (!info.enabled) { - return true; - } - return false; + public boolean filterApp(AppEntry entry) { + return !entry.info.enabled; } }; - public static final AppFilter ALL_ENABLED_FILTER = new AppFilter() { + public static final AppFilter FILTER_ALL_ENABLED = new AppFilter() { public void init() { } - + @Override - public boolean filterApp(ApplicationInfo info) { - if (info.enabled) { - return true; - } - return false; + 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; } }; @@ -398,6 +443,7 @@ public class ApplicationsState { static final int MSG_PACKAGE_SIZE_CHANGED = 4; static final int MSG_ALL_SIZES_COMPUTED = 5; static final int MSG_RUNNING_STATE_CHANGED = 6; + static final int MSG_LAUNCHER_INFO_CHANGED = 7; @Override public void handleMessage(Message msg) { @@ -436,6 +482,11 @@ public class ApplicationsState { msg.arg1 != 0); } } break; + case MSG_LAUNCHER_INFO_CHANGED: { + for (int i=0; i<mActiveSessions.size(); i++) { + mActiveSessions.get(i).mCallbacks.onLauncherInfoChanged(); + } + } break; } } } @@ -487,7 +538,7 @@ public class ApplicationsState { * 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 @@ -543,6 +594,12 @@ public class ApplicationsState { } } + ArrayList<AppEntry> getAllApps() { + synchronized (mEntriesMap) { + return new ArrayList<>(mAppEntries); + } + } + // Creates a new list of app entries with the given filter and comparator. ArrayList<AppEntry> rebuild(AppFilter filter, Comparator<AppEntry> comparator) { synchronized (mRebuildSync) { @@ -600,22 +657,21 @@ public class ApplicationsState { if (filter != null) { filter.init(); } - - List<ApplicationInfo> apps; + + List<AppEntry> apps; synchronized (mEntriesMap) { - apps = new ArrayList<ApplicationInfo>(mApplications); + apps = new ArrayList<>(mAppEntries); } ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>(); if (DEBUG) Log.i(TAG, "Rebuilding..."); for (int i=0; i<apps.size(); i++) { - ApplicationInfo info = apps.get(i); - if (filter == null || filter.filterApp(info)) { + AppEntry entry = apps.get(i); + if (filter == null || filter.filterApp(entry)) { synchronized (mEntriesMap) { if (DEBUG_LOCKING) Log.v(TAG, "rebuild acquired lock"); - AppEntry entry = getEntryLocked(info); entry.ensureLabel(mContext); - if (DEBUG) Log.i(TAG, "Using " + info.packageName + ": " + entry); + if (DEBUG) Log.i(TAG, "Using " + entry.info.packageName + ": " + entry); filteredApps.add(entry); if (DEBUG_LOCKING) Log.v(TAG, "rebuild releasing lock"); } @@ -757,7 +813,7 @@ public class ApplicationsState { return entry; } } - + void ensureIcon(AppEntry entry) { if (entry.icon != null) { return; @@ -766,7 +822,7 @@ public class ApplicationsState { entry.ensureIconLocked(mContext, mPm); } } - + void requestSize(String packageName, int userId) { if (DEBUG_LOCKING) Log.v(TAG, "requestSize about to acquire lock..."); synchronized (mEntriesMap) { @@ -790,7 +846,7 @@ public class ApplicationsState { } return sum; } - + int indexOfApplicationInfoLocked(String pkgName, int userId) { for (int i=mApplications.size()-1; i>=0; i--) { ApplicationInfo appInfo = mApplications.get(i); @@ -962,6 +1018,7 @@ public class ApplicationsState { 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; @@ -1074,8 +1131,39 @@ public class ApplicationsState { if (numDone >= 6) { sendEmptyMessage(MSG_LOAD_ENTRIES); } else { - sendEmptyMessage(MSG_LOAD_ICONS); + 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<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(launchIntent, + PackageManager.GET_DISABLED_COMPONENTS, userId); + synchronized (mEntriesMap) { + if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_LAUNCHER acquired lock"); + HashMap<String, AppEntry> 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; diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java index 555d18c..14d48c8 100644 --- a/src/com/android/settings/applications/ManageApplications.java +++ b/src/com/android/settings/applications/ManageApplications.java @@ -16,40 +16,22 @@ package com.android.settings.applications; -import static android.net.NetworkPolicyManager.POLICY_NONE; -import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; - import android.app.Activity; -import android.app.ActivityManager; -import android.app.AlertDialog; -import android.app.AppOpsManager; import android.app.Fragment; -import android.app.INotificationManager; -import android.content.ComponentName; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; -import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.res.TypedArray; -import android.net.NetworkPolicyManager; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; -import android.os.Handler; -import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.preference.PreferenceFrameLayout; import android.provider.Settings; -import android.support.v4.view.PagerAdapter; -import android.support.v4.view.PagerTabStrip; -import android.support.v4.view.ViewPager; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -61,34 +43,35 @@ import android.view.animation.AnimationUtils; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.Filter; import android.widget.Filterable; import android.widget.ListView; 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.Settings.RunningServicesActivity; -import com.android.settings.Settings.StorageUseActivity; +import com.android.settings.Settings.AllApplicationsActivity; +import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.ApplicationsState.AppEntry; -import com.android.settings.deviceinfo.StorageMeasurement; +import com.android.settings.applications.ApplicationsState.AppFilter; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; -import java.util.List; final class CanBeOnSdCardChecker { final IPackageManager mPm; int mInstallLocation; - + CanBeOnSdCardChecker() { mPm = IPackageManager.Stub.asInterface( ServiceManager.getService("package")); } - + void init() { try { mInstallLocation = mPm.getInstallLocation(); @@ -97,7 +80,7 @@ final class CanBeOnSdCardChecker { return; } } - + boolean check(ApplicationInfo info) { boolean canBe = false; if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { @@ -121,414 +104,407 @@ final class CanBeOnSdCardChecker { } } -interface AppClickListener { - void onItemClick(ManageApplications.TabInfo tab, AdapterView<?> parent, - View view, int position, long id); -} - /** * Activity to pick an application that will be used to display installation information and * options to uninstall/delete user data for system applications. This activity * can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE * intent. */ -public class ManageApplications extends Fragment implements - AppClickListener, DialogInterface.OnClickListener, DialogInterface.OnDismissListener { +public class ManageApplications extends Fragment implements OnItemClickListener, + OnItemSelectedListener { static final String TAG = "ManageApplications"; - static final boolean DEBUG = false; + static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final String EXTRA_LIST_TYPE = "currentListType"; private static final String EXTRA_SORT_ORDER = "sortOrder"; - private static final String EXTRA_SHOW_BACKGROUND = "showBackground"; - private static final String EXTRA_DEFAULT_LIST_TYPE = "defaultListType"; - private static final String EXTRA_RESET_DIALOG = "resetDialog"; // attributes used as keys when passing values to InstalledAppDetails activity public static final String APP_CHG = "chg"; // constant value that can be used to check return code from sub activity. private static final int INSTALLED_APP_DETAILS = 1; + private static final int ADVANCED_SETTINGS = 2; public static final int SIZE_TOTAL = 0; public static final int SIZE_INTERNAL = 1; public static final int SIZE_EXTERNAL = 2; + // Filter options used for displayed list of applications + // The order which they appear is the order they will show when spinner is present. + public static final int FILTER_APPS_DOWNLOADED_AND_LAUNCHER = 0; + public static final int FILTER_APPS_ALL = 1; + public static final int FILTER_APPS_ENABLED = 2; + public static final int FILTER_APPS_DISABLED = 3; + public static final int FILTER_APPS_PERSONAL = 4; + public static final int FILTER_APPS_WORK = 5; + + // This is the string labels for the filter modes above, the order must be kept in sync. + public static final int[] FILTER_LABELS = new int[] { + R.string.filter_all_apps, // Downloaded and launcher, spinner not shown in this case + R.string.filter_all_apps, // All apps + R.string.filter_enabled_apps, // Enabled + R.string.filter_apps_disabled, // Disabled + R.string.filter_personal_apps, // Personal + R.string.filter_work_apps, // Work + }; + // This is the actual mapping to filters from FILTER_ constants above, the order must + // be kept in sync. + public static final AppFilter[] FILTERS = new AppFilter[] { + ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER, // Downloaded and launcher + ApplicationsState.FILTER_EVERYTHING, // All apps + ApplicationsState.FILTER_ALL_ENABLED, // Enabled + ApplicationsState.FILTER_DISABLED, // Disabled + ApplicationsState.FILTER_PERSONAL, // Personal + ApplicationsState.FILTER_WORK, // Work + }; + // sort order that can be changed through the menu can be sorted alphabetically // or size(descending) private static final int MENU_OPTIONS_BASE = 0; - // Filter options used for displayed list of applications - public static final int FILTER_APPS_ALL = MENU_OPTIONS_BASE + 0; - public static final int FILTER_APPS_THIRD_PARTY = MENU_OPTIONS_BASE + 1; - public static final int FILTER_APPS_SDCARD = MENU_OPTIONS_BASE + 2; - public static final int FILTER_APPS_DISABLED = MENU_OPTIONS_BASE + 3; - - public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 4; - public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 5; - public static final int SHOW_RUNNING_SERVICES = MENU_OPTIONS_BASE + 6; - public static final int SHOW_BACKGROUND_PROCESSES = MENU_OPTIONS_BASE + 7; - public static final int RESET_APP_PREFERENCES = MENU_OPTIONS_BASE + 8; + public static final int SORT_ORDER_ALPHA = MENU_OPTIONS_BASE + 1; + public static final int SORT_ORDER_SIZE = MENU_OPTIONS_BASE + 2; + public static final int RESET_APP_PREFERENCES = MENU_OPTIONS_BASE + 3; // sort order private int mSortOrder = SORT_ORDER_ALPHA; - + private ApplicationsState mApplicationsState; - public static class TabInfo implements OnItemClickListener { - public final ManageApplications mOwner; - public final ApplicationsState mApplicationsState; - public final CharSequence mLabel; - public final int mListType; - public final int mFilter; - public final AppClickListener mClickListener; - public final CharSequence mInvalidSizeStr; - public final CharSequence mComputingSizeStr; - private final Bundle mSavedInstanceState; - - public ApplicationsAdapter mApplications; - public LayoutInflater mInflater; - public View mRootView; - - private IMediaContainerService mContainerService; - - private View mLoadingContainer; - - private View mListContainer; - - // ListView used to display list - private ListView mListView; - // Custom view used to display running processes - private RunningProcessesView mRunningProcessesView; - - //private LinearColorBar mColorBar; - //private TextView mStorageChartLabel; - //private TextView mUsedStorageText; - //private TextView mFreeStorageText; - private long mFreeStorage = 0, mAppStorage = 0, mTotalStorage = 0; - private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage; - - final Runnable mRunningProcessesAvail = new Runnable() { - public void run() { - handleRunningProcessesAvail(); - } - }; + public int mListType; + public int mFilter; - public TabInfo(ManageApplications owner, ApplicationsState apps, - CharSequence label, int listType, AppClickListener clickListener, - Bundle savedInstanceState) { - mOwner = owner; - mApplicationsState = apps; - mLabel = label; - mListType = listType; - switch (listType) { - case LIST_TYPE_DOWNLOADED: mFilter = FILTER_APPS_THIRD_PARTY; break; - case LIST_TYPE_SDCARD: mFilter = FILTER_APPS_SDCARD; break; - case LIST_TYPE_DISABLED: mFilter = FILTER_APPS_DISABLED; break; - default: mFilter = FILTER_APPS_ALL; break; - } - mClickListener = clickListener; - mInvalidSizeStr = owner.getActivity().getText(R.string.invalid_size_value); - mComputingSizeStr = owner.getActivity().getText(R.string.computing_size); - mSavedInstanceState = savedInstanceState; + public ApplicationsAdapter mApplications; + + private View mLoadingContainer; + + private View mListContainer; + + // ListView used to display list + private ListView mListView; + + // Size resource used for packages whose size computation failed for some reason + CharSequence mInvalidSizeStr; + + // layout inflater object used to inflate views + private LayoutInflater mInflater; + + private String mCurrentPkgName; + private int mCurrentUid; + + private Menu mOptionsMenu; + + public static final int LIST_TYPE_MAIN = 0; + public static final int LIST_TYPE_ALL = 1; + + private View mRootView; + + private View mSpinnerHeader; + private Spinner mFilterSpinner; + private FilterSpinnerAdapter mFilterAdapter; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication()); + + Intent intent = getActivity().getIntent(); + String action = intent.getAction(); + String className = getArguments() != null + ? getArguments().getString("classname") : null; + if (className == null) { + className = intent.getComponent().getClassName(); } + if (Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS.equals(action) + || className.equals(AllApplicationsActivity.class.getName())) { + mListType = LIST_TYPE_ALL; + } else { + mListType = LIST_TYPE_MAIN; + } + mFilter = getDefaultFilter(); - public void setContainerService(IMediaContainerService containerService) { - mContainerService = containerService; - updateStorageUsage(); + if (savedInstanceState != null) { + mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder); } - public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) { - if (mRootView != null) { - return mRootView; - } - mInflater = inflater; - mRootView = inflater.inflate(mListType == LIST_TYPE_RUNNING - ? R.layout.manage_applications_running - : R.layout.manage_applications_apps, null); - mLoadingContainer = mRootView.findViewById(R.id.loading_container); - mLoadingContainer.setVisibility(View.VISIBLE); - mListContainer = mRootView.findViewById(R.id.list_container); - if (mListContainer != null) { - // Create adapter and list view here - View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty); - ListView lv = (ListView) mListContainer.findViewById(android.R.id.list); - if (emptyView != null) { - lv.setEmptyView(emptyView); - } - lv.setOnItemClickListener(this); - lv.setSaveEnabled(true); - lv.setItemsCanFocus(true); - lv.setTextFilterEnabled(true); - mListView = lv; - mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter); - mListView.setAdapter(mApplications); - mListView.setRecyclerListener(mApplications); - //mColorBar = (LinearColorBar)mListContainer.findViewById(R.id.storage_color_bar); - //mStorageChartLabel = (TextView)mListContainer.findViewById(R.id.storageChartLabel); - //mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText); - //mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText); - Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false); - if (mFilter == FILTER_APPS_SDCARD) { - //mStorageChartLabel.setText(mOwner.getActivity().getText( - // R.string.sd_card_storage)); - } else { - //mStorageChartLabel.setText(mOwner.getActivity().getText( - // R.string.internal_storage)); - } - applyCurrentStorage(); - } - mRunningProcessesView = (RunningProcessesView)mRootView.findViewById( - R.id.running_processes); - if (mRunningProcessesView != null) { - mRunningProcessesView.doCreate(mSavedInstanceState); + mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value); + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // initialize the inflater + mInflater = inflater; + + createHeader(); + + mRootView = inflater.inflate(R.layout.manage_applications_apps, null); + mLoadingContainer = mRootView.findViewById(R.id.loading_container); + mLoadingContainer.setVisibility(View.VISIBLE); + mListContainer = mRootView.findViewById(R.id.list_container); + if (mListContainer != null) { + // Create adapter and list view here + View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty); + ListView lv = (ListView) mListContainer.findViewById(android.R.id.list); + if (emptyView != null) { + lv.setEmptyView(emptyView); } + lv.setOnItemClickListener(this); + lv.setSaveEnabled(true); + lv.setItemsCanFocus(true); + lv.setTextFilterEnabled(true); + mListView = lv; + mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter); + mListView.setAdapter(mApplications); + mListView.setRecyclerListener(mApplications); - return mRootView; + Utils.prepareCustomPreferencesList(container, mRootView, mListView, false); } - public void detachView() { - if (mRootView != null) { - ViewGroup group = (ViewGroup)mRootView.getParent(); - if (group != null) { - group.removeView(mRootView); - } - } + // We have to do this now because PreferenceFrameLayout looks at it + // only when the view is added. + if (container instanceof PreferenceFrameLayout) { + ((PreferenceFrameLayout.LayoutParams) mRootView.getLayoutParams()).removeBorders = true; } - public void resume(int sortOrder) { - if (mApplications != null) { - mApplications.resume(sortOrder); - } - if (mRunningProcessesView != null) { - boolean haveData = mRunningProcessesView.doResume(mOwner, mRunningProcessesAvail); - if (haveData) { - mRunningProcessesView.setVisibility(View.VISIBLE); - mLoadingContainer.setVisibility(View.INVISIBLE); - } else { - mLoadingContainer.setVisibility(View.VISIBLE); - } + return mRootView; + } + + private void createHeader() { + Activity activity = getActivity(); + View content = activity.findViewById(R.id.main_content); + ViewGroup contentParent = (ViewGroup) content.getParent(); + mSpinnerHeader = (ViewGroup) activity.getLayoutInflater() + .inflate(R.layout.apps_filter_spinner, contentParent, false); + mFilterSpinner = (Spinner) mSpinnerHeader.findViewById(R.id.filter_spinner); + mFilterAdapter = new FilterSpinnerAdapter(this); + mFilterSpinner.setAdapter(mFilterAdapter); + mFilterSpinner.setOnItemSelectedListener(this); + contentParent.addView(mSpinnerHeader, 0); + + mFilterAdapter.enableFilter(getDefaultFilter()); + if (mListType != LIST_TYPE_MAIN) { + if (UserManager.get(getActivity()).getUserProfiles().size() > 1) { + mFilterAdapter.enableFilter(FILTER_APPS_PERSONAL); + mFilterAdapter.enableFilter(FILTER_APPS_WORK); } } + } - public void pause() { - if (mApplications != null) { - mApplications.pause(); - } - if (mRunningProcessesView != null) { - mRunningProcessesView.doPause(); - } + private int getDefaultFilter() { + if (mListType == LIST_TYPE_MAIN) { + return FILTER_APPS_DOWNLOADED_AND_LAUNCHER; } + return FILTER_APPS_ALL; + } - public void release() { - if (mApplications != null) { - mApplications.release(); - } + @Override + public void onResume() { + super.onResume(); + updateView(); + updateOptionsMenu(); + if (mApplications != null) { + mApplications.resume(mSortOrder); } + } - void updateStorageUsage() { - // Make sure a callback didn't come at an inopportune time. - if (mOwner.getActivity() == null) return; - // Doesn't make sense for stuff that is not an app list. - if (mApplications == null) return; - - mFreeStorage = 0; - mAppStorage = 0; - mTotalStorage = 0; - - if (mFilter == FILTER_APPS_SDCARD) { - if (mContainerService != null) { - try { - final long[] stats = mContainerService.getFileSystemStats( - Environment.getExternalStorageDirectory().getPath()); - mTotalStorage = stats[0]; - mFreeStorage = stats[1]; - } catch (RemoteException e) { - Log.w(TAG, "Problem in container service", e); - } - } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(EXTRA_SORT_ORDER, mSortOrder); + } - if (mApplications != null) { - final int N = mApplications.getCount(); - for (int i=0; i<N; i++) { - ApplicationsState.AppEntry ae = mApplications.getAppEntry(i); - mAppStorage += ae.externalCodeSize + ae.externalDataSize - + ae.externalCacheSize; - } - } - } else { - if (mContainerService != null) { - try { - final long[] stats = mContainerService.getFileSystemStats( - Environment.getDataDirectory().getPath()); - mTotalStorage = stats[0]; - mFreeStorage = stats[1]; - } catch (RemoteException e) { - Log.w(TAG, "Problem in container service", e); - } - } + @Override + public void onPause() { + super.onPause(); + if (mApplications != null) { + mApplications.pause(); + } + } - final boolean emulatedStorage = Environment.isExternalStorageEmulated(); - if (mApplications != null) { - final int N = mApplications.getCount(); - for (int i=0; i<N; i++) { - ApplicationsState.AppEntry ae = mApplications.getAppEntry(i); - mAppStorage += ae.codeSize + ae.dataSize; - if (emulatedStorage) { - mAppStorage += ae.externalCodeSize + ae.externalDataSize; - } - } - } - mFreeStorage += mApplicationsState.sumCacheSizes(); - } + @Override + public void onDestroyView() { + super.onDestroyView(); - applyCurrentStorage(); + if (mApplications != null) { + mApplications.release(); } + mRootView = null; + } - void applyCurrentStorage() { - // If view hierarchy is not yet created, no views to update. - if (mRootView == null) { - return; - } - /* - if (mTotalStorage > 0) { - BidiFormatter bidiFormatter = BidiFormatter.getInstance(); - mColorBar.setRatios((mTotalStorage-mFreeStorage-mAppStorage)/(float)mTotalStorage, - mAppStorage/(float)mTotalStorage, mFreeStorage/(float)mTotalStorage); - long usedStorage = mTotalStorage - mFreeStorage; - if (mLastUsedStorage != usedStorage) { - mLastUsedStorage = usedStorage; - String sizeStr = bidiFormatter.unicodeWrap( - Formatter.formatShortFileSize(mOwner.getActivity(), usedStorage)); - mUsedStorageText.setText(mOwner.getActivity().getResources().getString( - R.string.service_foreground_processes, sizeStr)); - } - if (mLastFreeStorage != mFreeStorage) { - mLastFreeStorage = mFreeStorage; - String sizeStr = bidiFormatter.unicodeWrap( - Formatter.formatShortFileSize(mOwner.getActivity(), mFreeStorage)); - mFreeStorageText.setText(mOwner.getActivity().getResources().getString( - R.string.service_background_processes, sizeStr)); - } - } else { - mColorBar.setRatios(0, 0, 0); - if (mLastUsedStorage != -1) { - mLastUsedStorage = -1; - mUsedStorageText.setText(""); - } - if (mLastFreeStorage != -1) { - mLastFreeStorage = -1; - mFreeStorageText.setText(""); - } - } - */ + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) { + mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid)); } + } - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - mClickListener.onItemClick(this, parent, view, position, id); - } + // utility method used to start sub activity + private void startApplicationDetailsActivity() { + // 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))); + } - void handleRunningProcessesAvail() { - mLoadingContainer.startAnimation(AnimationUtils.loadAnimation( - mOwner.getActivity(), android.R.anim.fade_out)); - mRunningProcessesView.startAnimation(AnimationUtils.loadAnimation( - mOwner.getActivity(), android.R.anim.fade_in)); - mRunningProcessesView.setVisibility(View.VISIBLE); - mLoadingContainer.setVisibility(View.GONE); + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + mOptionsMenu = menu; + if (mListType == LIST_TYPE_MAIN) { + // Only show advanced options when in the main app list (from dashboard). + inflater.inflate(R.menu.manage_apps, menu); } + menu.add(0, SORT_ORDER_ALPHA, 1, R.string.sort_order_alpha) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + updateOptionsMenu(); } - private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); - private int mNumTabs; - TabInfo mCurTab = null; - // Size resource used for packages whose size computation failed for some reason - CharSequence mInvalidSizeStr; - private CharSequence mComputingSizeStr; - - // layout inflater object used to inflate views - private LayoutInflater mInflater; - - private String mCurrentPkgName; - private int mCurrentUid; - - private Menu mOptionsMenu; + @Override + public void onPrepareOptionsMenu(Menu menu) { + updateOptionsMenu(); + } + + @Override + public void onDestroyOptionsMenu() { + mOptionsMenu = null; + } - // These are for keeping track of activity and spinner switch state. - private boolean mActivityResumed; + void updateOptionsMenu() { + if (mOptionsMenu == null) { + return; + } + + if (mListType != LIST_TYPE_MAIN) { + // Allow sorting except on main apps list. + mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA); + mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE); + } else { + mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(false); + mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(false); + } + } - private static final int LIST_TYPE_MISSING = -1; - static final int LIST_TYPE_DOWNLOADED = 0; - static final int LIST_TYPE_RUNNING = 1; - static final int LIST_TYPE_SDCARD = 2; - static final int LIST_TYPE_ALL = 3; - static final int LIST_TYPE_DISABLED = 4; + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int menuId = item.getItemId(); + switch(item.getItemId()) { + case SORT_ORDER_ALPHA: + case SORT_ORDER_SIZE: + mSortOrder = menuId; + if (mApplications != null) { + mApplications.rebuild(mSortOrder); + } + break; + case R.id.advanced: + ((SettingsActivity) getActivity()).startPreferencePanel( + AdvancedAppSettings.class.getName(), null, R.string.advanced_apps, + null, this, ADVANCED_SETTINGS); + return true; + default: + // Handle the home button + return false; + } + updateOptionsMenu(); + return true; + } - private boolean mShowBackground = false; - - private int mDefaultListType = -1; + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + if (mApplications != null && mApplications.getCount() > position) { + ApplicationsState.AppEntry entry = mApplications.getAppEntry(position); + mCurrentPkgName = entry.info.packageName; + mCurrentUid = entry.info.uid; + startApplicationDetailsActivity(); + } + } - private ViewGroup mContentContainer; - private View mRootView; - private ViewPager mViewPager; - private ViewGroup mPinnedHeader; - private Spinner mSpinner; - private Context mContext; + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + mApplications.setFilter(mFilterAdapter.getFilter(position)); + } - AlertDialog mResetDialog; + @Override + public void onNothingSelected(AdapterView<?> parent) { + } - class MyPagerAdapter extends PagerAdapter - implements ViewPager.OnPageChangeListener { - int mCurPos = 0; + public void updateView() { + updateOptionsMenu(); + final Activity host = getActivity(); + if (host != null) { + host.invalidateOptionsMenu(); + } + } - @Override - public int getCount() { - return mNumTabs; + public void setHasDisabled(boolean hasDisabledApps) { + if (mListType == LIST_TYPE_MAIN) { + // No filtering on main app list. + return; } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - TabInfo tab = mTabs.get(position); - View root = tab.build(mInflater, mContentContainer, mRootView); - container.addView(root); - root.setTag(R.id.name, tab); - return root; + if (hasDisabledApps) { + mFilterAdapter.enableFilter(FILTER_APPS_ENABLED); + mFilterAdapter.enableFilter(FILTER_APPS_DISABLED); + } else { + mFilterAdapter.disableFilter(FILTER_APPS_ENABLED); + mFilterAdapter.disableFilter(FILTER_APPS_DISABLED); } + } - @Override - public void destroyItem(ViewGroup container, int position, Object object) { - container.removeView((View)object); + static class FilterSpinnerAdapter extends ArrayAdapter<CharSequence> { + + private final ManageApplications mManageApplications; + + // Use ArrayAdapter for view logic, but have our own list for managing + // the options available. + private final ArrayList<Integer> mFilterOptions = new ArrayList<>(); + + public FilterSpinnerAdapter(ManageApplications manageApplications) { + super(manageApplications.getActivity(), R.layout.filter_spinner_item); + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mManageApplications = manageApplications; } - @Override - public boolean isViewFromObject(View view, Object object) { - return view == object; + public int getFilter(int position) { + return mFilterOptions.get(position); } - @Override - public int getItemPosition(Object object) { - return super.getItemPosition(object); - //return ((TabInfo)((View)object).getTag(R.id.name)).mListType; + public void enableFilter(int filter) { + if (mFilterOptions.contains(filter)) return; + mFilterOptions.add(filter); + Collections.sort(mFilterOptions); + mManageApplications.mSpinnerHeader.setVisibility( + mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE); + notifyDataSetChanged(); } - @Override - public CharSequence getPageTitle(int position) { - return mTabs.get(position).mLabel; + public void disableFilter(int filter) { + if (!mFilterOptions.remove((Integer) filter)) { + return; + } + Collections.sort(mFilterOptions); + mManageApplications.mSpinnerHeader.setVisibility( + mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE); + notifyDataSetChanged(); } @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + public int getCount() { + return mFilterOptions.size(); } @Override - public void onPageSelected(int position) { - mCurPos = position; + public CharSequence getItem(int position) { + return getFilterString(mFilterOptions.get(position)); } - @Override - public void onPageScrollStateChanged(int state) { - if (state == ViewPager.SCROLL_STATE_IDLE) { - updateCurrentTab(mCurPos); - } + private CharSequence getFilterString(int filter) { + return mManageApplications.getString(FILTER_LABELS[filter]); } + } /* @@ -544,15 +520,14 @@ public class ManageApplications extends Fragment implements ApplicationsState.Callbacks, AbsListView.RecyclerListener { private final ApplicationsState mState; private final ApplicationsState.Session mSession; - private final TabInfo mTab; + private final ManageApplications mManageApplications; private final Context mContext; private final ArrayList<View> mActive = new ArrayList<View>(); - private final int mFilterMode; + private int mFilterMode; private ArrayList<ApplicationsState.AppEntry> mBaseEntries; private ArrayList<ApplicationsState.AppEntry> mEntries; private boolean mResumed; private int mLastSortMode=-1; - private boolean mWaitingForData; private int mWhichSize = SIZE_TOTAL; CharSequence mCurFilterPrefix; @@ -568,22 +543,28 @@ public class ManageApplications extends Fragment implements } @Override + @SuppressWarnings("unchecked") protected void publishResults(CharSequence constraint, FilterResults results) { mCurFilterPrefix = constraint; - mEntries = (ArrayList<ApplicationsState.AppEntry>)results.values; + mEntries = (ArrayList<ApplicationsState.AppEntry>) results.values; notifyDataSetChanged(); - mTab.updateStorageUsage(); } }; - public ApplicationsAdapter(ApplicationsState state, TabInfo tab, int filterMode) { + public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications, + int filterMode) { mState = state; mSession = state.newSession(this); - mTab = tab; - mContext = tab.mOwner.getActivity(); + mManageApplications = manageApplications; + mContext = manageApplications.getActivity(); mFilterMode = filterMode; } + public void setFilter(int filter) { + mFilterMode = filter; + rebuild(true); + } + public void resume(int sort) { if (DEBUG) Log.i(TAG, "Resume! mResumed=" + mResumed); if (!mResumed) { @@ -614,7 +595,7 @@ public class ManageApplications extends Fragment implements mLastSortMode = sort; rebuild(true); } - + public void rebuild(boolean eraseold) { if (DEBUG) Log.i(TAG, "Rebuilding app list..."); ApplicationsState.AppFilter filterObj; @@ -625,23 +606,7 @@ public class ManageApplications extends Fragment implements } else { mWhichSize = SIZE_INTERNAL; } - switch (mFilterMode) { - case FILTER_APPS_THIRD_PARTY: - filterObj = ApplicationsState.THIRD_PARTY_FILTER; - break; - case FILTER_APPS_SDCARD: - filterObj = ApplicationsState.ON_SD_CARD_FILTER; - if (!emulated) { - mWhichSize = SIZE_EXTERNAL; - } - break; - case FILTER_APPS_DISABLED: - filterObj = ApplicationsState.DISABLED_FILTER; - break; - default: - filterObj = ApplicationsState.ALL_ENABLED_FILTER; - break; - } + filterObj = FILTERS[mFilterMode]; switch (mLastSortMode) { case SORT_ORDER_SIZE: switch (mWhichSize) { @@ -673,16 +638,26 @@ public class ManageApplications extends Fragment implements mEntries = null; } notifyDataSetChanged(); - mTab.updateStorageUsage(); if (entries == null) { - mWaitingForData = true; - mTab.mListContainer.setVisibility(View.INVISIBLE); - mTab.mLoadingContainer.setVisibility(View.VISIBLE); + mManageApplications.mListContainer.setVisibility(View.INVISIBLE); + mManageApplications.mLoadingContainer.setVisibility(View.VISIBLE); } else { - mTab.mListContainer.setVisibility(View.VISIBLE); - mTab.mLoadingContainer.setVisibility(View.GONE); + mManageApplications.mListContainer.setVisibility(View.VISIBLE); + mManageApplications.mLoadingContainer.setVisibility(View.GONE); } + + mManageApplications.setHasDisabled(hasDisabledApps()); + } + + private boolean hasDisabledApps() { + ArrayList<AppEntry> allApps = mSession.getAllApps(); + for (int i = 0; i < allApps.size(); i++) { + if (!allApps.get(i).info.enabled) { + return true; + } + } + return false; } ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix, @@ -707,24 +682,22 @@ public class ManageApplications extends Fragment implements @Override public void onRunningStateChanged(boolean running) { - mTab.mOwner.getActivity().setProgressBarIndeterminateVisibility(running); + mManageApplications.getActivity().setProgressBarIndeterminateVisibility(running); } @Override public void onRebuildComplete(ArrayList<AppEntry> apps) { - if (mTab.mLoadingContainer.getVisibility() == View.VISIBLE) { - mTab.mLoadingContainer.startAnimation(AnimationUtils.loadAnimation( + if (mManageApplications.mLoadingContainer.getVisibility() == View.VISIBLE) { + mManageApplications.mLoadingContainer.startAnimation(AnimationUtils.loadAnimation( mContext, android.R.anim.fade_out)); - mTab.mListContainer.startAnimation(AnimationUtils.loadAnimation( + mManageApplications.mListContainer.startAnimation(AnimationUtils.loadAnimation( mContext, android.R.anim.fade_in)); } - mTab.mListContainer.setVisibility(View.VISIBLE); - mTab.mLoadingContainer.setVisibility(View.GONE); - mWaitingForData = false; + mManageApplications.mListContainer.setVisibility(View.VISIBLE); + mManageApplications.mLoadingContainer.setVisibility(View.GONE); mBaseEntries = apps; mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries); notifyDataSetChanged(); - mTab.updateStorageUsage(); } @Override @@ -744,9 +717,9 @@ public class ManageApplications extends Fragment implements AppViewHolder holder = (AppViewHolder)mActive.get(i).getTag(); if (holder.entry.info.packageName.equals(packageName)) { synchronized (holder.entry) { - holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize); + holder.updateSizeText(mManageApplications.mInvalidSizeStr, mWhichSize); } - if (holder.entry.info.packageName.equals(mTab.mOwner.mCurrentPkgName) + if (holder.entry.info.packageName.equals(mManageApplications.mCurrentPkgName) && mLastSortMode == SORT_ORDER_SIZE) { // We got the size information for the last app the // user viewed, and are sorting by size... they may @@ -754,28 +727,33 @@ public class ManageApplications extends Fragment implements // the list with the new size to reflect it to the user. rebuild(false); } - mTab.updateStorageUsage(); return; } } } @Override + public void onLauncherInfoChanged() { + if (mFilterMode == FILTER_APPS_DOWNLOADED_AND_LAUNCHER) { + rebuild(false); + } + } + + @Override public void onAllSizesComputed() { if (mLastSortMode == SORT_ORDER_SIZE) { rebuild(false); } - mTab.updateStorageUsage(); } - + public int getCount() { return mEntries != null ? mEntries.size() : 0; } - + public Object getItem(int position) { return mEntries.get(position); } - + public ApplicationsState.AppEntry getAppEntry(int position) { return mEntries.get(position); } @@ -783,11 +761,12 @@ public class ManageApplications extends Fragment implements public long getItemId(int position) { return mEntries.get(position).id; } - + public View getView(int position, View convertView, ViewGroup parent) { // A ViewHolder keeps references to children views to avoid unnecessary calls // to findViewById() on each row. - AppViewHolder holder = AppViewHolder.createOrRecycle(mTab.mInflater, convertView); + AppViewHolder holder = AppViewHolder.createOrRecycle(mManageApplications.mInflater, + convertView); convertView = holder.rootView; // Bind the data efficiently with the holder @@ -801,7 +780,7 @@ public class ManageApplications extends Fragment implements if (entry.icon != null) { holder.appIcon.setImageDrawable(entry.icon); } - holder.updateSizeText(mTab.mInvalidSizeStr, mWhichSize); + holder.updateSizeText(mManageApplications.mInvalidSizeStr, mWhichSize); if ((entry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { holder.disabled.setVisibility(View.VISIBLE); holder.disabled.setText(R.string.not_installed); @@ -811,13 +790,7 @@ public class ManageApplications extends Fragment implements } else { holder.disabled.setVisibility(View.GONE); } - if (mFilterMode == FILTER_APPS_SDCARD) { - holder.checkBox.setVisibility(View.VISIBLE); - holder.checkBox.setChecked((entry.info.flags - & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); - } else { - holder.checkBox.setVisibility(View.GONE); - } + holder.checkBox.setVisibility(View.GONE); } mActive.remove(convertView); mActive.add(convertView); @@ -834,463 +807,4 @@ public class ManageApplications extends Fragment implements mActive.remove(view); } } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setHasOptionsMenu(true); - - mContext = getActivity(); - mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication()); - Intent intent = getActivity().getIntent(); - String action = intent.getAction(); - int defaultListType = LIST_TYPE_DOWNLOADED; - String className = getArguments() != null - ? getArguments().getString("classname") : null; - if (className == null) { - className = intent.getComponent().getClassName(); - } - if (className.equals(RunningServicesActivity.class.getName()) - || className.endsWith(".RunningServices")) { - defaultListType = LIST_TYPE_RUNNING; - } else if (className.equals(StorageUseActivity.class.getName()) - || Intent.ACTION_MANAGE_PACKAGE_STORAGE.equals(action) - || className.endsWith(".StorageUse")) { - mSortOrder = SORT_ORDER_SIZE; - defaultListType = LIST_TYPE_ALL; - } else if (android.provider.Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS.equals(action)) { - // Select the all-apps list, with the default sorting - defaultListType = LIST_TYPE_ALL; - } - - if (savedInstanceState != null) { - mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder); - int tmp = savedInstanceState.getInt(EXTRA_DEFAULT_LIST_TYPE, -1); - if (tmp != -1) defaultListType = tmp; - mShowBackground = savedInstanceState.getBoolean(EXTRA_SHOW_BACKGROUND, false); - } - - mDefaultListType = defaultListType; - - final Intent containerIntent = new Intent().setComponent( - StorageMeasurement.DEFAULT_CONTAINER_COMPONENT); - getActivity().bindService(containerIntent, mContainerConnection, Context.BIND_AUTO_CREATE); - - mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value); - mComputingSizeStr = getActivity().getText(R.string.computing_size); - - TabInfo tab = new TabInfo(this, mApplicationsState, - getActivity().getString(R.string.filter_apps_third_party), - LIST_TYPE_DOWNLOADED, this, savedInstanceState); - mTabs.add(tab); - - if (!Environment.isExternalStorageEmulated()) { - tab = new TabInfo(this, mApplicationsState, - getActivity().getString(R.string.filter_apps_onsdcard), - LIST_TYPE_SDCARD, this, savedInstanceState); - mTabs.add(tab); - } - - tab = new TabInfo(this, mApplicationsState, - getActivity().getString(R.string.filter_apps_running), - LIST_TYPE_RUNNING, this, savedInstanceState); - mTabs.add(tab); - - tab = new TabInfo(this, mApplicationsState, - getActivity().getString(R.string.filter_apps_all), - LIST_TYPE_ALL, this, savedInstanceState); - mTabs.add(tab); - - tab = new TabInfo(this, mApplicationsState, - getActivity().getString(R.string.filter_apps_disabled), - LIST_TYPE_DISABLED, this, savedInstanceState); - mTabs.add(tab); - - mNumTabs = mTabs.size(); - } - - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - // initialize the inflater - mInflater = inflater; - - View rootView = mInflater.inflate(R.layout.manage_applications_content, - container, false); - mContentContainer = container; - mRootView = rootView; - mViewPager = (ViewPager) rootView.findViewById(R.id.pager); - MyPagerAdapter adapter = new MyPagerAdapter(); - mViewPager.setAdapter(adapter); - mViewPager.setOnPageChangeListener(adapter); - PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs); - - // This should be set in the XML layout, but PagerTabStrip lives in - // support-v4 and doesn't have styleable attributes. - final TypedArray ta = tabs.getContext().obtainStyledAttributes( - new int[] { android.R.attr.colorAccent }); - final int colorAccent = ta.getColor(0, 0); - ta.recycle(); - - tabs.setTabIndicatorColorResource(colorAccent); - - // We have to do this now because PreferenceFrameLayout looks at it - // only when the view is added. - if (container instanceof PreferenceFrameLayout) { - ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true; - } - - if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) { - buildResetDialog(); - } - - if (savedInstanceState == null) { - // First time init: make sure view pager is showing the correct tab. - int extraCurrentListType = getActivity().getIntent().getIntExtra(EXTRA_LIST_TYPE, - LIST_TYPE_MISSING); - int currentListType = (extraCurrentListType != LIST_TYPE_MISSING) - ? extraCurrentListType : mDefaultListType; - for (int i = 0; i < mNumTabs; i++) { - TabInfo tab = mTabs.get(i); - if (tab.mListType == currentListType) { - mViewPager.setCurrentItem(i); - break; - } - } - } - - return rootView; - } - - @Override - public void onStart() { - super.onStart(); - } - - @Override - public void onResume() { - super.onResume(); - mActivityResumed = true; - updateCurrentTab(mViewPager.getCurrentItem()); - updateNumTabs(); - updateOptionsMenu(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(EXTRA_SORT_ORDER, mSortOrder); - if (mDefaultListType != -1) { - outState.putInt(EXTRA_DEFAULT_LIST_TYPE, mDefaultListType); - } - outState.putBoolean(EXTRA_SHOW_BACKGROUND, mShowBackground); - if (mResetDialog != null) { - outState.putBoolean(EXTRA_RESET_DIALOG, true); - } - } - - @Override - public void onPause() { - super.onPause(); - mActivityResumed = false; - for (int i=0; i<mTabs.size(); i++) { - mTabs.get(i).pause(); - } - } - - @Override - public void onStop() { - super.onStop(); - if (mResetDialog != null) { - mResetDialog.dismiss(); - mResetDialog = null; - } - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - - // We are going to keep the tab data structures around, but they - // are no longer attached to their view hierarchy. - for (int i=0; i<mTabs.size(); i++) { - mTabs.get(i).detachView(); - mTabs.get(i).release(); - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) { - mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid)); - } - } - - private void updateNumTabs() { - int newNum = mApplicationsState.haveDisabledApps() ? mTabs.size() : (mTabs.size()-1); - if (newNum != mNumTabs) { - mNumTabs = newNum; - if (mViewPager != null) { - mViewPager.getAdapter().notifyDataSetChanged(); - } - } - } - - TabInfo tabForType(int type) { - for (int i = 0; i < mTabs.size(); i++) { - TabInfo tab = mTabs.get(i); - if (tab.mListType == type) { - return tab; - } - } - return null; - } - - // utility method used to start sub activity - private void startApplicationDetailsActivity() { - // 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 - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - mOptionsMenu = menu; - // note: icons removed for now because the cause the new action - // bar UI to be very confusing. - menu.add(0, SORT_ORDER_ALPHA, 1, R.string.sort_order_alpha) - //.setIcon(android.R.drawable.ic_menu_sort_alphabetically) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - menu.add(0, SORT_ORDER_SIZE, 2, R.string.sort_order_size) - //.setIcon(android.R.drawable.ic_menu_sort_by_size) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - menu.add(0, SHOW_RUNNING_SERVICES, 3, R.string.show_running_services) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - menu.add(0, SHOW_BACKGROUND_PROCESSES, 3, R.string.show_background_processes) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - menu.add(0, RESET_APP_PREFERENCES, 4, R.string.reset_app_preferences) - .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - updateOptionsMenu(); - } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - updateOptionsMenu(); - } - - @Override - public void onDestroyOptionsMenu() { - mOptionsMenu = null; - } - - @Override - public void onDestroy() { - getActivity().unbindService(mContainerConnection); - super.onDestroy(); - } - - void updateOptionsMenu() { - if (mOptionsMenu == null) { - return; - } - - /* - * The running processes screen doesn't use the mApplicationsAdapter - * so bringing up this menu in that case doesn't make any sense. - */ - if (mCurTab != null && mCurTab.mListType == LIST_TYPE_RUNNING) { - TabInfo tab = tabForType(LIST_TYPE_RUNNING); - boolean showingBackground = tab != null && tab.mRunningProcessesView != null - ? tab.mRunningProcessesView.mAdapter.getShowBackground() : false; - mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(false); - mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(false); - mOptionsMenu.findItem(SHOW_RUNNING_SERVICES).setVisible(showingBackground); - mOptionsMenu.findItem(SHOW_BACKGROUND_PROCESSES).setVisible(!showingBackground); - mOptionsMenu.findItem(RESET_APP_PREFERENCES).setVisible(false); - mShowBackground = showingBackground; - } else { - mOptionsMenu.findItem(SORT_ORDER_ALPHA).setVisible(mSortOrder != SORT_ORDER_ALPHA); - mOptionsMenu.findItem(SORT_ORDER_SIZE).setVisible(mSortOrder != SORT_ORDER_SIZE); - mOptionsMenu.findItem(SHOW_RUNNING_SERVICES).setVisible(false); - mOptionsMenu.findItem(SHOW_BACKGROUND_PROCESSES).setVisible(false); - mOptionsMenu.findItem(RESET_APP_PREFERENCES).setVisible(true); - } - } - - void buildResetDialog() { - if (mResetDialog == null) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(R.string.reset_app_preferences_title); - builder.setMessage(R.string.reset_app_preferences_desc); - builder.setPositiveButton(R.string.reset_app_preferences_button, this); - builder.setNegativeButton(R.string.cancel, null); - mResetDialog = builder.show(); - mResetDialog.setOnDismissListener(this); - } - } - - @Override - public void onDismiss(DialogInterface dialog) { - if (mResetDialog == dialog) { - mResetDialog = null; - } - } - - - @Override - public void onClick(DialogInterface dialog, int which) { - if (mResetDialog == dialog) { - final PackageManager pm = getActivity().getPackageManager(); - final IPackageManager mIPm = IPackageManager.Stub.asInterface( - ServiceManager.getService("package")); - final INotificationManager nm = INotificationManager.Stub.asInterface( - ServiceManager.getService(Context.NOTIFICATION_SERVICE)); - final NetworkPolicyManager npm = NetworkPolicyManager.from(getActivity()); - final AppOpsManager aom = (AppOpsManager)getActivity().getSystemService( - Context.APP_OPS_SERVICE); - final Handler handler = new Handler(getActivity().getMainLooper()); - (new AsyncTask<Void, Void, Void>() { - @Override protected Void doInBackground(Void... params) { - List<ApplicationInfo> apps = pm.getInstalledApplications( - PackageManager.GET_DISABLED_COMPONENTS); - for (int i=0; i<apps.size(); i++) { - ApplicationInfo app = apps.get(i); - try { - if (DEBUG) Log.v(TAG, "Enabling notifications: " + app.packageName); - nm.setNotificationsEnabledForPackage(app.packageName, app.uid, true); - } catch (android.os.RemoteException ex) { - } - if (!app.enabled) { - if (DEBUG) Log.v(TAG, "Enabling app: " + app.packageName); - if (pm.getApplicationEnabledSetting(app.packageName) - == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { - pm.setApplicationEnabledSetting(app.packageName, - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, - PackageManager.DONT_KILL_APP); - } - } - } - try { - mIPm.resetPreferredActivities(UserHandle.myUserId()); - } catch (RemoteException e) { - } - aom.resetAllModes(); - final int[] restrictedUids = npm.getUidsWithPolicy( - POLICY_REJECT_METERED_BACKGROUND); - final int currentUserId = ActivityManager.getCurrentUser(); - for (int uid : restrictedUids) { - // Only reset for current user - if (UserHandle.getUserId(uid) == currentUserId) { - if (DEBUG) Log.v(TAG, "Clearing data policy: " + uid); - npm.setUidPolicy(uid, POLICY_NONE); - } - } - handler.post(new Runnable() { - @Override public void run() { - if (DEBUG) Log.v(TAG, "Done clearing"); - if (getActivity() != null && mActivityResumed) { - if (DEBUG) Log.v(TAG, "Updating UI!"); - for (int i=0; i<mTabs.size(); i++) { - TabInfo tab = mTabs.get(i); - if (tab.mApplications != null) { - tab.mApplications.pause(); - } - } - if (mCurTab != null) { - mCurTab.resume(mSortOrder); - } - } - } - }); - return null; - } - }).execute(); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int menuId = item.getItemId(); - if ((menuId == SORT_ORDER_ALPHA) || (menuId == SORT_ORDER_SIZE)) { - mSortOrder = menuId; - if (mCurTab != null && mCurTab.mApplications != null) { - mCurTab.mApplications.rebuild(mSortOrder); - } - } else if (menuId == SHOW_RUNNING_SERVICES) { - mShowBackground = false; - if (mCurTab != null && mCurTab.mRunningProcessesView != null) { - mCurTab.mRunningProcessesView.mAdapter.setShowBackground(false); - } - } else if (menuId == SHOW_BACKGROUND_PROCESSES) { - mShowBackground = true; - if (mCurTab != null && mCurTab.mRunningProcessesView != null) { - mCurTab.mRunningProcessesView.mAdapter.setShowBackground(true); - } - } else if (menuId == RESET_APP_PREFERENCES) { - buildResetDialog(); - } else { - // Handle the home button - return false; - } - updateOptionsMenu(); - return true; - } - - public void onItemClick(TabInfo tab, AdapterView<?> parent, View view, int position, - long id) { - if (tab.mApplications != null && tab.mApplications.getCount() > position) { - ApplicationsState.AppEntry entry = tab.mApplications.getAppEntry(position); - mCurrentPkgName = entry.info.packageName; - mCurrentUid = entry.info.uid; - startApplicationDetailsActivity(); - } - } - - public void updateCurrentTab(int position) { - TabInfo tab = mTabs.get(position); - mCurTab = tab; - - // Put things in the correct paused/resumed state. - if (mActivityResumed) { - mCurTab.build(mInflater, mContentContainer, mRootView); - mCurTab.resume(mSortOrder); - } else { - mCurTab.pause(); - } - for (int i=0; i<mTabs.size(); i++) { - TabInfo t = mTabs.get(i); - if (t != mCurTab) { - t.pause(); - } - } - - mCurTab.updateStorageUsage(); - updateOptionsMenu(); - final Activity host = getActivity(); - if (host != null) { - host.invalidateOptionsMenu(); - } - } - - private volatile IMediaContainerService mContainerService; - - private final ServiceConnection mContainerConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - mContainerService = IMediaContainerService.Stub.asInterface(service); - for (int i=0; i<mTabs.size(); i++) { - mTabs.get(i).setContainerService(mContainerService); - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mContainerService = null; - } - }; } diff --git a/src/com/android/settings/search/Ranking.java b/src/com/android/settings/search/Ranking.java index 0022338..e418e9b 100644 --- a/src/com/android/settings/search/Ranking.java +++ b/src/com/android/settings/search/Ranking.java @@ -29,6 +29,7 @@ import com.android.settings.SecuritySettings; import com.android.settings.WallpaperTypeSettings; import com.android.settings.WirelessSettings; import com.android.settings.accessibility.AccessibilitySettings; +import com.android.settings.applications.AdvancedAppSettings; import com.android.settings.bluetooth.BluetoothSettings; import com.android.settings.deviceinfo.Memory; import com.android.settings.deviceinfo.UsbSettings; @@ -67,16 +68,17 @@ public final class Ranking { public static final int RANK_NOTIFICATIONS = 9; public static final int RANK_STORAGE = 10; public static final int RANK_POWER_USAGE = 11; - public static final int RANK_USERS = 12; - public static final int RANK_LOCATION = 13; - public static final int RANK_SECURITY = 14; - public static final int RANK_IME = 15; - public static final int RANK_PRIVACY = 16; - public static final int RANK_DATE_TIME = 17; - public static final int RANK_ACCESSIBILITY = 18; - public static final int RANK_PRINTING = 19; - public static final int RANK_DEVELOPEMENT = 20; - public static final int RANK_DEVICE_INFO = 21; + public static final int RANK_APPS = 12; + public static final int RANK_USERS = 13; + public static final int RANK_LOCATION = 14; + public static final int RANK_SECURITY = 15; + public static final int RANK_IME = 16; + public static final int RANK_PRIVACY = 17; + public static final int RANK_DATE_TIME = 18; + public static final int RANK_ACCESSIBILITY = 19; + public static final int RANK_PRINTING = 20; + public static final int RANK_DEVELOPEMENT = 21; + public static final int RANK_DEVICE_INFO = 22; public static final int RANK_UNDEFINED = -1; public static final int RANK_OTHERS = 1024; @@ -129,6 +131,9 @@ public final class Ranking { sRankMap.put(PowerUsageSummary.class.getName(), RANK_POWER_USAGE); sRankMap.put(BatterySaverSettings.class.getName(), RANK_POWER_USAGE); + // Advanced app settings + sRankMap.put(AdvancedAppSettings.class.getName(), RANK_APPS); + // Users sRankMap.put(UserSettings.class.getName(), RANK_USERS); diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index d774469..d5aa4b7 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -31,6 +31,7 @@ import com.android.settings.SecuritySettings; import com.android.settings.WallpaperTypeSettings; import com.android.settings.WirelessSettings; import com.android.settings.accessibility.AccessibilitySettings; +import com.android.settings.applications.AdvancedAppSettings; import com.android.settings.bluetooth.BluetoothSettings; import com.android.settings.deviceinfo.Memory; import com.android.settings.deviceinfo.UsbSettings; @@ -188,6 +189,13 @@ public final class SearchIndexableResources { BatterySaverSettings.class.getName(), R.drawable.ic_settings_battery)); + sResMap.put(AdvancedAppSettings.class.getName(), + new SearchIndexableResource( + Ranking.getRankForClassName(AdvancedAppSettings.class.getName()), + R.xml.advanced_apps, + AdvancedAppSettings.class.getName(), + R.drawable.ic_settings_applications)); + sResMap.put(UserSettings.class.getName(), new SearchIndexableResource( Ranking.getRankForClassName(UserSettings.class.getName()), |