[Dynamic Home] Make a new page for all top level settings
Since we are moving conditionals/suggestions to a different place, there is no need to use DashboardSummary to display top level settings any more. We can simplify a lot of code for top level settings and reduce it to a standard DashboardFragment. - Create a new DashboardFragment + xml for all top level internal items - Add a PreferenceController to provide summary for Network & internet item. - Mark a bunch of things deprecated for future work. Bug: 110405144 Test: robotests Change-Id: I9f778777131c28eb836b722e089e026a59f5ddc6
This commit is contained in:
@@ -170,6 +170,7 @@
|
||||
<item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
|
||||
<item name="colorPrimaryDark">@*android:color/primary_dark_device_default_settings_light</item>
|
||||
<item name="colorAccent">@*android:color/accent_device_default_light</item>
|
||||
<item name="preferenceTheme">@style/PreferenceTheme</item>
|
||||
</style>
|
||||
|
||||
<!--TODO(b/111875856) This theme will be useless, when we add real activity/fragment to handle the full screen for WifiDialog -->
|
||||
|
108
res/xml/top_level_settings.xml
Normal file
108
res/xml/top_level_settings.xml
Normal file
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="top_level_settings"
|
||||
android:title="@string/settings_label_launcher">
|
||||
|
||||
<Preference
|
||||
android:key="top_level_network"
|
||||
android:title="@string/network_dashboard_title"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_network"
|
||||
android:fragment="com.android.settings.network.NetworkDashboardFragment"
|
||||
settings:controller="com.android.settings.network.TopLevelNetworkEntryPreferenceController"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_connected_devices"
|
||||
android:title="@string/connected_devices_dashboard_title"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_connected_device"
|
||||
android:fragment="com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_apps_and_notifs"
|
||||
android:title="@string/app_and_notification_dashboard_title"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_apps"
|
||||
android:fragment="com.android.settings.applications.AppAndNotificationDashboardFragment"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_battery"
|
||||
android:title="@string/power_usage_summary_title"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_battery"
|
||||
android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_display"
|
||||
android:title="@string/display_settings"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_display"
|
||||
android:fragment="com.android.settings.DisplaySettings"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_sound"
|
||||
android:title="@string/sound_settings"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_sound"
|
||||
android:fragment="com.android.settings.notification.SoundSettings"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_storage"
|
||||
android:title="@string/storage_settings"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_storage"
|
||||
android:fragment="com.android.settings.deviceinfo.StorageSettings"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_security"
|
||||
android:title="@string/security_settings_title"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_security"
|
||||
android:fragment="com.android.settings.security.SecuritySettings"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_accounts"
|
||||
android:title="@string/account_dashboard_title"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_accounts"
|
||||
android:fragment="com.android.settings.accounts.AccountDashboardFragment"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_accessibility"
|
||||
android:title="@string/accessibility_settings"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_accessibility"
|
||||
android:fragment="com.android.settings.accessibility.AccessibilitySettings"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_system"
|
||||
android:title="@string/header_category_system"
|
||||
android:summary="@string/summary_placeholder"
|
||||
android:icon="@drawable/ic_homepage_system_dashboard"
|
||||
android:fragment="com.android.settings.system.SystemDashboardFragment"/>
|
||||
|
||||
<Preference
|
||||
android:key="top_level_support"
|
||||
android:summary="@string/support_summary"
|
||||
android:title="@string/page_tab_title_support"
|
||||
android:icon="@drawable/ic_homepage_support"/>
|
||||
|
||||
</PreferenceScreen>
|
@@ -42,6 +42,12 @@ import com.android.settingslib.utils.ThreadUtils;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TODO(b/110405144): Remove this when all top level settings are converted to PreferenceControllers
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public class SummaryLoader {
|
||||
private static final boolean DEBUG = DashboardSummary.DEBUG;
|
||||
private static final String TAG = "SummaryLoader";
|
||||
|
@@ -26,6 +26,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toolbar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsHomepageActivity;
|
||||
@@ -39,8 +41,6 @@ import com.google.android.material.bottomappbar.BottomAppBar;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class HomepageFragment extends InstrumentedFragment {
|
||||
|
||||
private static final String TAG = "HomepageFragment";
|
||||
@@ -70,7 +70,7 @@ public class HomepageFragment extends InstrumentedFragment {
|
||||
|
||||
private void setupBottomBar() {
|
||||
final Activity activity = getActivity();
|
||||
mSearchButton = (FloatingActionButton) activity.findViewById(R.id.search_fab);
|
||||
mSearchButton = activity.findViewById(R.id.search_fab);
|
||||
|
||||
mSearchButton.setOnClickListener(v -> {
|
||||
final Intent intent = SearchFeatureProvider.SEARCH_UI_INTENT;
|
||||
@@ -79,7 +79,7 @@ public class HomepageFragment extends InstrumentedFragment {
|
||||
startActivityForResult(intent, 0 /* requestCode */);
|
||||
});
|
||||
mBottomSheetBehavior = BottomSheetBehavior.from(activity.findViewById(R.id.bottom_sheet));
|
||||
final BottomAppBar bottomBar = (BottomAppBar) activity.findViewById(R.id.bar);
|
||||
final BottomAppBar bottomBar = activity.findViewById(R.id.bar);
|
||||
bottomBar.setOnClickListener(v -> {
|
||||
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
});
|
||||
@@ -87,7 +87,7 @@ public class HomepageFragment extends InstrumentedFragment {
|
||||
final int screenWidthpx = getResources().getDisplayMetrics().widthPixels;
|
||||
final View searchbar = activity.findViewById(R.id.search_bar_container);
|
||||
final View bottombar = activity.findViewById(R.id.bar);
|
||||
final Toolbar searchActionBar = (Toolbar) activity.findViewById(R.id.search_action_bar);
|
||||
final Toolbar searchActionBar = activity.findViewById(R.id.search_action_bar);
|
||||
searchActionBar.setNavigationIcon(R.drawable.ic_search_floating_24dp);
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ public class HomepageFragment extends InstrumentedFragment {
|
||||
@Override
|
||||
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
||||
if (!mBottomFragmentLoaded) {
|
||||
// TODO(b/110405144): Switch to {@link TopLevelSettings} when it's ready.
|
||||
SettingsHomepageActivity.switchToFragment(getActivity(),
|
||||
R.id.bottom_sheet_fragment, DashboardSummary.class.getName());
|
||||
mBottomFragmentLoaded = true;
|
||||
|
110
src/com/android/settings/homepage/TopLevelSettings.java
Normal file
110
src/com/android/settings/homepage/TopLevelSettings.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.homepage;
|
||||
|
||||
import static com.android.settings.search.actionbar.SearchMenuController
|
||||
.NEED_SEARCH_ICON_IN_ACTION_BAR;
|
||||
import static com.android.settingslib.search.SearchIndexable.MOBILE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.core.instrumentation.Instrumentable;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SearchIndexable(forTarget = MOBILE)
|
||||
public class TopLevelSettings extends DashboardFragment implements
|
||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||
|
||||
private static final String TAG = "TopLevelSettings";
|
||||
|
||||
public TopLevelSettings() {
|
||||
final Bundle args = new Bundle();
|
||||
// Disable the search icon because this page uses a full search view in actionbar.
|
||||
args.putBoolean(NEED_SEARCH_ICON_IN_ACTION_BAR, false);
|
||||
setArguments(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.top_level_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.DASHBOARD_SUMMARY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHelpResource() {
|
||||
// Disable the help icon because this page uses a full search view in actionbar.
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getCallbackFragment() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) {
|
||||
new SubSettingLauncher(getActivity())
|
||||
.setDestination(pref.getFragment())
|
||||
.setArguments(pref.getExtras())
|
||||
.setSourceMetricsCategory(caller instanceof Instrumentable
|
||||
? ((Instrumentable) caller).getMetricsCategory()
|
||||
: Instrumentable.METRICS_CATEGORY_UNKNOWN)
|
||||
.setTitleRes(-1)
|
||||
.launch();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableResource> getXmlResourcesToIndex(
|
||||
Context context, boolean enabled) {
|
||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||
sir.xmlResId = R.xml.top_level_settings;
|
||||
return Arrays.asList(sir);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
// Never searchable, all entries in this page are already indexed elsewhere.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
@@ -149,6 +149,7 @@ public class NetworkDashboardFragment extends DashboardFragment implements
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(b/110405144): Remove SummaryProvider
|
||||
@VisibleForTesting
|
||||
static class SummaryProvider implements SummaryLoader.SummaryProvider {
|
||||
|
||||
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.network;
|
||||
|
||||
import android.content.Context;
|
||||
import android.icu.text.ListFormatter;
|
||||
import android.text.BidiFormatter;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.wifi.WifiMasterSwitchPreferenceController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TopLevelNetworkEntryPreferenceController extends BasePreferenceController {
|
||||
|
||||
private final WifiMasterSwitchPreferenceController mWifiPreferenceController;
|
||||
private final MobileNetworkPreferenceController mMobileNetworkPreferenceController;
|
||||
private final TetherPreferenceController mTetherPreferenceController;
|
||||
|
||||
public TopLevelNetworkEntryPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mMobileNetworkPreferenceController = new MobileNetworkPreferenceController(mContext);
|
||||
mTetherPreferenceController = new TetherPreferenceController(
|
||||
mContext, null /* lifecycle */);
|
||||
mWifiPreferenceController = new WifiMasterSwitchPreferenceController(
|
||||
mContext, null /* metrics */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE_UNSEARCHABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final String wifiSummary = BidiFormatter.getInstance()
|
||||
.unicodeWrap(mContext.getString(R.string.wifi_settings_title));
|
||||
final String mobileSummary = mContext.getString(
|
||||
R.string.network_dashboard_summary_mobile);
|
||||
final String dataUsageSummary = mContext.getString(
|
||||
R.string.network_dashboard_summary_data_usage);
|
||||
final String hotspotSummary = mContext.getString(
|
||||
R.string.network_dashboard_summary_hotspot);
|
||||
|
||||
final List<String> summaries = new ArrayList<>();
|
||||
if (mWifiPreferenceController.isAvailable()
|
||||
&& !TextUtils.isEmpty(wifiSummary)) {
|
||||
summaries.add(wifiSummary);
|
||||
}
|
||||
if (mMobileNetworkPreferenceController.isAvailable() && !TextUtils.isEmpty(mobileSummary)) {
|
||||
summaries.add(mobileSummary);
|
||||
}
|
||||
if (!TextUtils.isEmpty(dataUsageSummary)) {
|
||||
summaries.add(dataUsageSummary);
|
||||
}
|
||||
if (mTetherPreferenceController.isAvailable()
|
||||
&& !TextUtils.isEmpty(hotspotSummary)) {
|
||||
summaries.add(hotspotSummary);
|
||||
}
|
||||
return ListFormatter.getInstance().format(summaries);
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.network;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtils;
|
||||
import com.android.settings.wifi.WifiMasterSwitchPreferenceController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(shadows = ShadowRestrictedLockUtils.class)
|
||||
public class TopLevelNetworkEntryPreferenceControllerTest {
|
||||
|
||||
@Mock
|
||||
private WifiMasterSwitchPreferenceController mWifiPreferenceController;
|
||||
@Mock
|
||||
private MobileNetworkPreferenceController mMobileNetworkPreferenceController;
|
||||
@Mock
|
||||
private TetherPreferenceController mTetherPreferenceController;
|
||||
|
||||
private Context mContext;
|
||||
private TopLevelNetworkEntryPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new TopLevelNetworkEntryPreferenceController(mContext, "test_key");
|
||||
|
||||
ReflectionHelpers.setField(mController, "mWifiPreferenceController",
|
||||
mWifiPreferenceController);
|
||||
ReflectionHelpers.setField(mController, "mMobileNetworkPreferenceController",
|
||||
mMobileNetworkPreferenceController);
|
||||
ReflectionHelpers.setField(mController, "mTetherPreferenceController",
|
||||
mTetherPreferenceController);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSummary_hasMobileAndHotspot_shouldReturnMobileSummary() {
|
||||
when(mWifiPreferenceController.isAvailable()).thenReturn(true);
|
||||
when(mMobileNetworkPreferenceController.isAvailable()).thenReturn(true);
|
||||
when(mTetherPreferenceController.isAvailable()).thenReturn(true);
|
||||
|
||||
assertThat(mController.getSummary())
|
||||
.isEqualTo("Wi\u2011Fi, mobile, data usage, and hotspot");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSummary_noMobileOrHotspot_shouldReturnSimpleSummary() {
|
||||
when(mWifiPreferenceController.isAvailable()).thenReturn(true);
|
||||
when(mMobileNetworkPreferenceController.isAvailable()).thenReturn(false);
|
||||
when(mTetherPreferenceController.isAvailable()).thenReturn(false);
|
||||
|
||||
assertThat(mController.getSummary())
|
||||
.isEqualTo("Wi\u2011Fi and data usage");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user