Merge "Fix Data Saver page crashed when rotate" into udc-dev
diff --git a/src/com/android/settings/datausage/DataSaverSummary.java b/src/com/android/settings/datausage/DataSaverSummary.java
deleted file mode 100644
index 67644a6..0000000
--- a/src/com/android/settings/datausage/DataSaverSummary.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2016 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.datausage;
-
-import android.app.Application;
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.icu.text.MessageFormat;
-import android.os.Bundle;
-import android.telephony.SubscriptionManager;
-import android.widget.Switch;
-
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppStateBaseBridge.Callback;
-import com.android.settings.datausage.DataSaverBackend.Listener;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.widget.SettingsMainSwitchBar;
-import com.android.settingslib.applications.ApplicationsState;
-import com.android.settingslib.applications.ApplicationsState.AppEntry;
-import com.android.settingslib.applications.ApplicationsState.Callbacks;
-import com.android.settingslib.applications.ApplicationsState.Session;
-import com.android.settingslib.search.SearchIndexable;
-import com.android.settingslib.widget.OnMainSwitchChangeListener;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-@SearchIndexable
-public class DataSaverSummary extends SettingsPreferenceFragment
- implements OnMainSwitchChangeListener, Listener, Callback, Callbacks {
-
- private static final String KEY_UNRESTRICTED_ACCESS = "unrestricted_access";
-
- private SettingsMainSwitchBar mSwitchBar;
- private DataSaverBackend mDataSaverBackend;
- private Preference mUnrestrictedAccess;
- private ApplicationsState mApplicationsState;
- private AppStateDataUsageBridge mDataUsageBridge;
- private Session mSession;
-
- // Flag used to avoid infinite loop due if user switch it on/off too quicky.
- private boolean mSwitching;
-
- private Runnable mLoadAppRunnable = () -> {
- mApplicationsState = ApplicationsState.getInstance(
- (Application) getContext().getApplicationContext());
- mDataUsageBridge = new AppStateDataUsageBridge(mApplicationsState, this, mDataSaverBackend);
- mSession = mApplicationsState.newSession(this, getSettingsLifecycle());
- mDataUsageBridge.resume(true /* forceLoadAllApps */);
- };
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- if (!isDataSaverVisible(getContext())) {
- finishFragment();
- return;
- }
-
- addPreferencesFromResource(R.xml.data_saver);
- mUnrestrictedAccess = findPreference(KEY_UNRESTRICTED_ACCESS);
- mDataSaverBackend = new DataSaverBackend(getContext());
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar();
- mSwitchBar.setTitle(getContext().getString(R.string.data_saver_switch_title));
- mSwitchBar.show();
- mSwitchBar.addOnSwitchChangeListener(this);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mDataSaverBackend.refreshAllowlist();
- mDataSaverBackend.refreshDenylist();
- mDataSaverBackend.addListener(this);
- if (mDataUsageBridge != null) {
- mDataUsageBridge.resume(true /* forceLoadAllApps */);
- } else {
- getView().post(mLoadAppRunnable);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mDataSaverBackend.remListener(this);
- if (mDataUsageBridge != null) {
- mDataUsageBridge.pause();
- }
- }
-
- @Override
- public void onSwitchChanged(Switch switchView, boolean isChecked) {
- synchronized (this) {
- if (mSwitching) {
- return;
- }
- mSwitching = true;
- mDataSaverBackend.setDataSaverEnabled(isChecked);
- }
- }
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.DATA_SAVER_SUMMARY;
- }
-
- @Override
- public int getHelpResource() {
- return R.string.help_url_data_saver;
- }
-
- @Override
- public void onDataSaverChanged(boolean isDataSaving) {
- synchronized (this) {
- mSwitchBar.setChecked(isDataSaving);
- mSwitching = false;
- }
- }
-
- @Override
- public void onAllowlistStatusChanged(int uid, boolean isAllowlisted) {
- }
-
- @Override
- public void onDenylistStatusChanged(int uid, boolean isDenylisted) {
- }
-
- @Override
- public void onExtraInfoUpdated() {
- updateUnrestrictedAccessSummary();
- }
-
- @Override
- public void onRunningStateChanged(boolean running) {
-
- }
-
- @Override
- public void onPackageListChanged() {
-
- }
-
- @Override
- public void onRebuildComplete(ArrayList<AppEntry> apps) {
-
- }
-
- @Override
- public void onPackageIconChanged() {
-
- }
-
- @Override
- public void onPackageSizeChanged(String packageName) {
-
- }
-
- @Override
- public void onAllSizesComputed() {
- updateUnrestrictedAccessSummary();
- }
-
- @Override
- public void onLauncherInfoChanged() {
- updateUnrestrictedAccessSummary();
- }
-
- @Override
- public void onLoadEntriesCompleted() {
-
- }
-
- private void updateUnrestrictedAccessSummary() {
- if (!isAdded() || isFinishingOrDestroyed() || mSession == null) return;
-
- int count = 0;
- for (AppEntry entry : mSession.getAllApps()) {
- if (!ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(entry)) {
- continue;
- }
- if (entry.extraInfo != null && ((AppStateDataUsageBridge.DataUsageState)
- entry.extraInfo).isDataSaverAllowlisted) {
- count++;
- }
- }
- MessageFormat msgFormat = new MessageFormat(
- getResources().getString(R.string.data_saver_unrestricted_summary),
- Locale.getDefault());
- Map<String, Object> arguments = new HashMap<>();
- arguments.put("count", count);
- mUnrestrictedAccess.setSummary(msgFormat.format(arguments));
- }
-
- public static boolean isDataSaverVisible(Context context) {
- return context.getResources()
- .getBoolean(R.bool.config_show_data_saver);
- }
-
- public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider(R.xml.data_saver) {
-
- @Override
- protected boolean isPageSearchEnabled(Context context) {
- return isDataSaverVisible(context)
- && DataUsageUtils.hasMobileData(context)
- && DataUsageUtils.getDefaultSubscriptionId(context)
- != SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- }
- };
-}
diff --git a/src/com/android/settings/datausage/DataSaverSummary.kt b/src/com/android/settings/datausage/DataSaverSummary.kt
new file mode 100644
index 0000000..1d9cbb7
--- /dev/null
+++ b/src/com/android/settings/datausage/DataSaverSummary.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2023 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.datausage
+
+import android.app.Application
+import android.app.settings.SettingsEnums
+import android.content.Context
+import android.os.Bundle
+import android.telephony.SubscriptionManager
+import android.widget.Switch
+import androidx.lifecycle.lifecycleScope
+import androidx.preference.Preference
+import com.android.settings.R
+import com.android.settings.SettingsActivity
+import com.android.settings.SettingsPreferenceFragment
+import com.android.settings.applications.AppStateBaseBridge
+import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState
+import com.android.settings.search.BaseSearchIndexProvider
+import com.android.settings.widget.SettingsMainSwitchBar
+import com.android.settingslib.applications.ApplicationsState
+import com.android.settingslib.search.SearchIndexable
+import com.android.settingslib.spa.framework.util.formatString
+import kotlinx.coroutines.launch
+
+@SearchIndexable
+class DataSaverSummary : SettingsPreferenceFragment() {
+ private lateinit var switchBar: SettingsMainSwitchBar
+ private lateinit var dataSaverBackend: DataSaverBackend
+ private lateinit var unrestrictedAccess: Preference
+ private var dataUsageBridge: AppStateDataUsageBridge? = null
+ private var session: ApplicationsState.Session? = null
+
+ // Flag used to avoid infinite loop due if user switch it on/off too quick.
+ private var switching = false
+
+ override fun onCreate(bundle: Bundle?) {
+ super.onCreate(bundle)
+
+ if (!requireContext().isDataSaverVisible()) {
+ finishFragment()
+ return
+ }
+
+ addPreferencesFromResource(R.xml.data_saver)
+ unrestrictedAccess = findPreference(KEY_UNRESTRICTED_ACCESS)!!
+ dataSaverBackend = DataSaverBackend(requireContext())
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ switchBar = (activity as SettingsActivity).switchBar.apply {
+ setTitle(getString(R.string.data_saver_switch_title))
+ show()
+ addOnSwitchChangeListener { _: Switch, isChecked: Boolean ->
+ onSwitchChanged(isChecked)
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ dataSaverBackend.refreshAllowlist()
+ dataSaverBackend.refreshDenylist()
+ dataSaverBackend.addListener(dataSaverBackendListener)
+ dataUsageBridge?.resume(/* forceLoadAllApps= */ true)
+ ?: viewLifecycleOwner.lifecycleScope.launch {
+ val applicationsState = ApplicationsState.getInstance(
+ requireContext().applicationContext as Application
+ )
+ dataUsageBridge = AppStateDataUsageBridge(
+ applicationsState, dataUsageBridgeCallbacks, dataSaverBackend
+ )
+ session =
+ applicationsState.newSession(applicationsStateCallbacks, settingsLifecycle)
+ dataUsageBridge?.resume(/* forceLoadAllApps= */ true)
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ dataSaverBackend.remListener(dataSaverBackendListener)
+ dataUsageBridge?.pause()
+ }
+
+ private fun onSwitchChanged(isChecked: Boolean) {
+ synchronized(this) {
+ if (!switching) {
+ switching = true
+ dataSaverBackend.isDataSaverEnabled = isChecked
+ }
+ }
+ }
+
+ override fun getMetricsCategory() = SettingsEnums.DATA_SAVER_SUMMARY
+
+ override fun getHelpResource() = R.string.help_url_data_saver
+
+ private val dataSaverBackendListener = object : DataSaverBackend.Listener {
+ override fun onDataSaverChanged(isDataSaving: Boolean) {
+ synchronized(this) {
+ switchBar.isChecked = isDataSaving
+ switching = false
+ }
+ }
+
+ override fun onAllowlistStatusChanged(uid: Int, isAllowlisted: Boolean) {}
+
+ override fun onDenylistStatusChanged(uid: Int, isDenylisted: Boolean) {}
+ }
+
+ private val dataUsageBridgeCallbacks = AppStateBaseBridge.Callback {
+ updateUnrestrictedAccessSummary()
+ }
+
+ private val applicationsStateCallbacks = object : ApplicationsState.Callbacks {
+ override fun onRunningStateChanged(running: Boolean) {}
+
+ override fun onPackageListChanged() {}
+
+ override fun onRebuildComplete(apps: ArrayList<ApplicationsState.AppEntry>?) {}
+
+ override fun onPackageIconChanged() {}
+
+ override fun onPackageSizeChanged(packageName: String?) {}
+
+ override fun onAllSizesComputed() {
+ updateUnrestrictedAccessSummary()
+ }
+
+ override fun onLauncherInfoChanged() {
+ updateUnrestrictedAccessSummary()
+ }
+
+ override fun onLoadEntriesCompleted() {}
+ }
+
+ private fun updateUnrestrictedAccessSummary() {
+ if (!isAdded || isFinishingOrDestroyed) return
+ val allApps = session?.allApps ?: return
+ val count = allApps.count {
+ ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(it) &&
+ (it.extraInfo as? DataUsageState)?.isDataSaverAllowlisted == true
+ }
+ unrestrictedAccess.summary =
+ resources.formatString(R.string.data_saver_unrestricted_summary, "count" to count)
+ }
+
+ companion object {
+ private const val KEY_UNRESTRICTED_ACCESS = "unrestricted_access"
+
+ private fun Context.isDataSaverVisible(): Boolean =
+ resources.getBoolean(R.bool.config_show_data_saver)
+
+ @JvmField
+ val SEARCH_INDEX_DATA_PROVIDER = object : BaseSearchIndexProvider(R.xml.data_saver) {
+ override fun isPageSearchEnabled(context: Context): Boolean =
+ context.isDataSaverVisible() &&
+ DataUsageUtils.hasMobileData(context) &&
+ (DataUsageUtils.getDefaultSubscriptionId(context) !=
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ }
+ }
+}
\ No newline at end of file