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