Merge "Implement new Manage Apps list"
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 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 @@
}
@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.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 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 @@
// 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 @@
long externalSize;
boolean mounted;
-
+
+ boolean hasLauncherEntry;
+
String getNormalizedLabel() {
if (normalizedLabel != null) {
return normalizedLabel;
@@ -128,7 +133,7 @@
this.sizeStale = true;
ensureLabel(context);
}
-
+
void ensureLabel(Context context) {
if (this.label == null || !this.mounted) {
if (!this.apkFile.exists()) {
@@ -141,7 +146,7 @@
}
}
}
-
+
boolean ensureIconLocked(Context context, PackageManager pm) {
if (this.icon == null) {
if (this.apkFile.exists()) {
@@ -175,13 +180,6 @@
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 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(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;
+ } else if (entry.hasLauncherEntry) {
return true;
}
return false;
}
};
- public static final AppFilter ON_SD_CARD_FILTER = new AppFilter() {
+ 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_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 @@
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 @@
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 @@
* 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 @@
}
}
+ 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 @@
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 @@
return entry;
}
}
-
+
void ensureIcon(AppEntry entry) {
if (entry.icon != null) {
return;
@@ -766,7 +822,7 @@
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 @@
}
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 @@
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,9 +1131,40 @@
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;
synchronized (mEntriesMap) {
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.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 @@
return;
}
}
-
+
boolean check(ApplicationInfo info) {
boolean canBe = false;
if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
@@ -121,414 +104,407 @@
}
}
-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 int mListType;
+ public int mFilter;
- public ApplicationsAdapter mApplications;
- public LayoutInflater mInflater;
- public View mRootView;
+ public ApplicationsAdapter mApplications;
- private IMediaContainerService mContainerService;
+ private View mLoadingContainer;
- private View mLoadingContainer;
+ private View mListContainer;
- 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 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 void setContainerService(IMediaContainerService containerService) {
- mContainerService = containerService;
- updateStorageUsage();
- }
-
- 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);
- }
-
- return mRootView;
- }
-
- public void detachView() {
- if (mRootView != null) {
- ViewGroup group = (ViewGroup)mRootView.getParent();
- if (group != null) {
- group.removeView(mRootView);
- }
- }
- }
-
- 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);
- }
- }
- }
-
- public void pause() {
- if (mApplications != null) {
- mApplications.pause();
- }
- if (mRunningProcessesView != null) {
- mRunningProcessesView.doPause();
- }
- }
-
- public void release() {
- if (mApplications != null) {
- mApplications.release();
- }
- }
-
- 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);
- }
- }
-
- 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);
- }
- }
-
- 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();
- }
-
- applyCurrentStorage();
- }
-
- 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 onItemClick(AdapterView<?> parent, View view, int position, long id) {
- mClickListener.onItemClick(this, parent, view, position, id);
- }
-
- 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);
- }
- }
- private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
- private int mNumTabs;
- TabInfo mCurTab = null;
+ // ListView used to display list
+ private ListView mListView;
// 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;
- // These are for keeping track of activity and spinner switch state.
- private boolean mActivityResumed;
+ public static final int LIST_TYPE_MAIN = 0;
+ public static final int LIST_TYPE_ALL = 1;
- 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;
-
- private boolean mShowBackground = false;
-
- private int mDefaultListType = -1;
-
- private ViewGroup mContentContainer;
private View mRootView;
- private ViewPager mViewPager;
- private ViewGroup mPinnedHeader;
- private Spinner mSpinner;
- private Context mContext;
- AlertDialog mResetDialog;
+ private View mSpinnerHeader;
+ private Spinner mFilterSpinner;
+ private FilterSpinnerAdapter mFilterAdapter;
- class MyPagerAdapter extends PagerAdapter
- implements ViewPager.OnPageChangeListener {
- int mCurPos = 0;
+ @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();
+
+ if (savedInstanceState != null) {
+ mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder);
+ }
+
+ 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);
+
+ Utils.prepareCustomPreferencesList(container, mRootView, mListView, false);
+ }
+
+ // 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;
+ }
+
+ 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);
+ }
+ }
+ }
+
+ private int getDefaultFilter() {
+ if (mListType == LIST_TYPE_MAIN) {
+ return FILTER_APPS_DOWNLOADED_AND_LAUNCHER;
+ }
+ return FILTER_APPS_ALL;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateView();
+ updateOptionsMenu();
+ if (mApplications != null) {
+ mApplications.resume(mSortOrder);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(EXTRA_SORT_ORDER, mSortOrder);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mApplications != null) {
+ mApplications.pause();
+ }
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+
+ if (mApplications != null) {
+ mApplications.release();
+ }
+ mRootView = null;
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
+ mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid));
+ }
+ }
+
+ // 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;
+ 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();
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ updateOptionsMenu();
+ }
+
+ @Override
+ public void onDestroyOptionsMenu() {
+ mOptionsMenu = null;
+ }
+
+ 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);
+ }
+ }
+
+ @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;
+ }
+
+ @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();
+ }
+ }
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ mApplications.setFilter(mFilterAdapter.getFilter(position));
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+
+ public void updateView() {
+ updateOptionsMenu();
+ final Activity host = getActivity();
+ if (host != null) {
+ host.invalidateOptionsMenu();
+ }
+ }
+
+ public void setHasDisabled(boolean hasDisabledApps) {
+ if (mListType == LIST_TYPE_MAIN) {
+ // No filtering on main app list.
+ return;
+ }
+ if (hasDisabledApps) {
+ mFilterAdapter.enableFilter(FILTER_APPS_ENABLED);
+ mFilterAdapter.enableFilter(FILTER_APPS_DISABLED);
+ } else {
+ mFilterAdapter.disableFilter(FILTER_APPS_ENABLED);
+ mFilterAdapter.disableFilter(FILTER_APPS_DISABLED);
+ }
+ }
+
+ 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;
+ }
+
+ public int getFilter(int position) {
+ return mFilterOptions.get(position);
+ }
+
+ 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();
+ }
+
+ 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 int getCount() {
- return mNumTabs;
- }
-
- @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;
+ return mFilterOptions.size();
}
@Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView((View)object);
+ public CharSequence getItem(int position) {
+ return getFilterString(mFilterOptions.get(position));
}
- @Override
- public boolean isViewFromObject(View view, Object object) {
- return view == object;
+ private CharSequence getFilterString(int filter) {
+ return mManageApplications.getString(FILTER_LABELS[filter]);
}
- @Override
- public int getItemPosition(Object object) {
- return super.getItemPosition(object);
- //return ((TabInfo)((View)object).getTag(R.id.name)).mListType;
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- return mTabs.get(position).mLabel;
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- }
-
- @Override
- public void onPageSelected(int position) {
- mCurPos = position;
- }
-
- @Override
- public void onPageScrollStateChanged(int state) {
- if (state == ViewPager.SCROLL_STATE_IDLE) {
- updateCurrentTab(mCurPos);
- }
- }
}
/*
@@ -544,15 +520,14 @@
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 @@
}
@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 @@
mLastSortMode = sort;
rebuild(true);
}
-
+
public void rebuild(boolean eraseold) {
if (DEBUG) Log.i(TAG, "Rebuilding app list...");
ApplicationsState.AppFilter filterObj;
@@ -625,23 +606,7 @@
} 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 @@
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 @@
@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 @@
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 @@
// 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 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 @@
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 @@
} 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 @@
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.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 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 @@
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.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 @@
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()),