diff --git a/res/layout/settings_base_layout.xml b/res/layout/settings_base_layout.xml new file mode 100644 index 00000000000..7216d7660aa --- /dev/null +++ b/res/layout/settings_base_layout.xml @@ -0,0 +1,35 @@ + + + + + + diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 3794d0eb6a5..711cb215d6d 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -52,6 +52,7 @@ import com.android.internal.util.ArrayUtils; import com.android.settings.Settings.WifiSettingsActivity; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.backup.BackupSettingsActivity; +import com.android.settings.core.SettingsBaseActivity; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.gateway.SettingsGateway; import com.android.settings.dashboard.DashboardFeatureProvider; @@ -64,7 +65,6 @@ import com.android.settingslib.core.instrumentation.Instrumentable; import com.android.settingslib.core.instrumentation.SharedPreferencesLogger; import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.SettingsDrawerActivity; import com.android.settingslib.utils.ThreadUtils; import java.util.ArrayList; @@ -76,7 +76,8 @@ import androidx.preference.Preference; import androidx.preference.PreferenceFragment; import androidx.preference.PreferenceManager; -public class SettingsActivity extends SettingsDrawerActivity + +public class SettingsActivity extends SettingsBaseActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback, ButtonBarHandler, FragmentManager.OnBackStackChangedListener { @@ -606,7 +607,7 @@ public class SettingsActivity extends SettingsDrawerActivity private void updateTilesList() { // Generally the items that are will be changing from these updates will // not be in the top list of tiles, so run it in the background and the - // SettingsDrawerActivity will pick up on the updates automatically. + // SettingsBaseActivity will pick up on the updates automatically. AsyncTask.execute(new Runnable() { @Override public void run() { diff --git a/src/com/android/settings/backup/BackupSettingsHelper.java b/src/com/android/settings/backup/BackupSettingsHelper.java index 53406fef756..33832169290 100644 --- a/src/com/android/settings/backup/BackupSettingsHelper.java +++ b/src/com/android/settings/backup/BackupSettingsHelper.java @@ -152,7 +152,6 @@ public class BackupSettingsHelper { } private Intent getIntentForDefaultBackupSettings() { - // Extra needed by {@link SettingsDrawerActivity} to show the back button navigation. return new Intent(mContext, PrivacySettingsActivity.class); } diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java new file mode 100644 index 00000000000..2cce467291b --- /dev/null +++ b/src/com/android/settings/core/SettingsBaseActivity.java @@ -0,0 +1,211 @@ +/** + * Copyright (C) 2018 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.core; + +import android.annotation.LayoutRes; +import android.annotation.Nullable; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.TypedArray; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.ArraySet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager.LayoutParams; +import android.widget.Toolbar; + +import com.android.settings.R; +import com.android.settingslib.drawer.CategoryManager; +import com.android.settingslib.drawer.TileUtils; + +import java.util.ArrayList; +import java.util.List; + +import androidx.fragment.app.FragmentActivity; + +public class SettingsBaseActivity extends FragmentActivity { + + protected static final boolean DEBUG_TIMING = false; + private static final String TAG = "SettingsBaseActivity"; + private static final String DATA_SCHEME_PKG = "package"; + + // Serves as a temporary list of tiles to ignore until we heard back from the PM that they + // are disabled. + private static ArraySet sTileBlacklist = new ArraySet<>(); + + private final PackageReceiver mPackageReceiver = new PackageReceiver(); + private final List mCategoryListeners = new ArrayList<>(); + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final long startTime = System.currentTimeMillis(); + + final TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme); + if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) { + getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + requestWindowFeature(Window.FEATURE_NO_TITLE); + } + super.setContentView(R.layout.settings_base_layout); + + final Toolbar toolbar = findViewById(R.id.action_bar); + if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) { + toolbar.setVisibility(View.GONE); + return; + } + setActionBar(toolbar); + + if (DEBUG_TIMING) { + Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + + " ms"); + } + } + + @Override + public boolean onNavigateUp() { + if (!super.onNavigateUp()) { + finish(); + } + return true; + } + + @Override + protected void onResume() { + super.onResume(); + final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REPLACED); + filter.addDataScheme(DATA_SCHEME_PKG); + registerReceiver(mPackageReceiver, filter); + + new CategoriesUpdateTask().execute(); + } + + @Override + protected void onPause() { + unregisterReceiver(mPackageReceiver); + super.onPause(); + } + + public void addCategoryListener(CategoryListener listener) { + mCategoryListeners.add(listener); + } + + public void remCategoryListener(CategoryListener listener) { + mCategoryListeners.remove(listener); + } + + @Override + public void setContentView(@LayoutRes int layoutResID) { + final ViewGroup parent = findViewById(R.id.content_frame); + if (parent != null) { + parent.removeAllViews(); + } + LayoutInflater.from(this).inflate(layoutResID, parent); + } + + @Override + public void setContentView(View view) { + ((ViewGroup) findViewById(R.id.content_frame)).addView(view); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + ((ViewGroup) findViewById(R.id.content_frame)).addView(view, params); + } + + private void onCategoriesChanged() { + final int N = mCategoryListeners.size(); + for (int i = 0; i < N; i++) { + mCategoryListeners.get(i).onCategoriesChanged(); + } + } + + /** + * @return whether or not the enabled state actually changed. + */ + public boolean setTileEnabled(ComponentName component, boolean enabled) { + final PackageManager pm = getPackageManager(); + int state = pm.getComponentEnabledSetting(component); + boolean isEnabled = state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + if (isEnabled != enabled || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + if (enabled) { + sTileBlacklist.remove(component); + } else { + sTileBlacklist.add(component); + } + pm.setComponentEnabledSetting(component, enabled + ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + return true; + } + return false; + } + + /** + * Updates dashboard categories. Only necessary to call this after setTileEnabled + */ + public void updateCategories() { + new CategoriesUpdateTask().execute(); + } + + public String getSettingPkg() { + return TileUtils.SETTING_PKG; + } + + public interface CategoryListener { + void onCategoriesChanged(); + } + + private class CategoriesUpdateTask extends AsyncTask { + + private final CategoryManager mCategoryManager; + + public CategoriesUpdateTask() { + mCategoryManager = CategoryManager.get(SettingsBaseActivity.this); + } + + @Override + protected Void doInBackground(Void... params) { + mCategoryManager.reloadAllCategories(SettingsBaseActivity.this, getSettingPkg()); + return null; + } + + @Override + protected void onPostExecute(Void result) { + mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist); + onCategoriesChanged(); + } + } + + private class PackageReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + new CategoriesUpdateTask().execute(); + } + } +} diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java index ecf905eff00..67ffb76b9f1 100644 --- a/src/com/android/settings/dashboard/DashboardFragment.java +++ b/src/com/android/settings/dashboard/DashboardFragment.java @@ -27,13 +27,13 @@ import android.util.Log; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerListHelper; +import com.android.settings.core.SettingsBaseActivity; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.Indexable; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.SettingsDrawerActivity; import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.TileUtils; @@ -52,7 +52,7 @@ import androidx.preference.PreferenceScreen; * Base fragment for dashboard style UI containing a list of static and dynamic setting items. */ public abstract class DashboardFragment extends SettingsPreferenceFragment - implements SettingsDrawerActivity.CategoryListener, Indexable, + implements SettingsBaseActivity.CategoryListener, Indexable, SummaryLoader.SummaryConsumer { private static final String TAG = "DashboardFragment"; @@ -145,9 +145,9 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment mSummaryLoader.setListening(true); } final Activity activity = getActivity(); - if (activity instanceof SettingsDrawerActivity) { + if (activity instanceof SettingsBaseActivity) { mListeningToCategoryChange = true; - ((SettingsDrawerActivity) activity).addCategoryListener(this); + ((SettingsBaseActivity) activity).addCategoryListener(this); } } @@ -197,8 +197,8 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment } if (mListeningToCategoryChange) { final Activity activity = getActivity(); - if (activity instanceof SettingsDrawerActivity) { - ((SettingsDrawerActivity) activity).remCategoryListener(this); + if (activity instanceof SettingsBaseActivity) { + ((SettingsBaseActivity) activity).remCategoryListener(this); } mListeningToCategoryChange = false; } diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java index 0bb4ce2898c..1b9b75f7139 100644 --- a/src/com/android/settings/dashboard/DashboardSummary.java +++ b/src/com/android/settings/dashboard/DashboardSummary.java @@ -30,6 +30,8 @@ import android.view.ViewGroup; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.core.InstrumentedFragment; +import com.android.settings.core.SettingsBaseActivity; +import com.android.settings.core.SettingsBaseActivity.CategoryListener; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.dashboard.conditional.ConditionManager; import com.android.settings.dashboard.conditional.ConditionManager.ConditionListener; @@ -40,8 +42,6 @@ import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.ActionBarShadowController; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.SettingsDrawerActivity; -import com.android.settingslib.drawer.SettingsDrawerActivity.CategoryListener; import com.android.settingslib.suggestions.SuggestionControllerMixin; import com.android.settingslib.utils.ThreadUtils; @@ -138,7 +138,7 @@ public class DashboardSummary extends InstrumentedFragment long startTime = System.currentTimeMillis(); super.onResume(); - ((SettingsDrawerActivity) getActivity()).addCategoryListener(this); + ((SettingsBaseActivity) getActivity()).addCategoryListener(this); mSummaryLoader.setListening(true); final int metricsCategory = getMetricsCategory(); for (Condition c : mConditionManager.getConditions()) { @@ -156,7 +156,7 @@ public class DashboardSummary extends InstrumentedFragment public void onPause() { super.onPause(); - ((SettingsDrawerActivity) getActivity()).remCategoryListener(this); + ((SettingsBaseActivity) getActivity()).remCategoryListener(this); mSummaryLoader.setListening(false); for (Condition c : mConditionManager.getConditions()) { if (c.shouldShow()) {