Merge "Fix Data Saver page crashed when rotate" into udc-dev am: bf9ba71cba
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/22898015 Change-Id: I0da6f5cb3bf8f959e2c0f3fa206b9998bc744290 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
176
src/com/android/settings/datausage/DataSaverSummary.kt
Normal file
176
src/com/android/settings/datausage/DataSaverSummary.kt
Normal file
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user